解析Android框架之Volley源码

Volley简单使用

我这里是以依赖架包的形式 ,大家也可以以gradle的形式进行依赖。

好了,接下来上代码了.....

//获取volley的请求对象
        RequestQueue requestQueue = Volley.newRequestQueue(getApplicationContext());
        StringRequest stringRequest = new StringRequest(StringRequest.Method.GET, "http://www.baidu.com", new Response.Listener<String>() {
            @Override
            public void onResponse(String s) {
                Log.d("MainActivity", "----->" + s);

            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError volleyError) {
                Log.d("MainActivity", "---volleyError-->" + volleyError);
            }
        });
        requestQueue.add(stringRequest);

从代码可以看出,首先newRequestQueue来获取到一个请求队列,然后在将StringRequest这个请求添加到请求队列中,就可以了,就是这么简单。当然请求不值StringRequest,还有JsonObjectRequest ,ImageRequest等等但是用法都是一样的,这里就不贴代码了。Volley的简单使用就这样可以进行请求了。是不是很简单

Volley执行原理

但是这个不是本篇的重点,重点是分析一下这些是怎么执行的。先上一张图

我们先看看newRequestQueue这个内部是怎么执行的,代码一开始连续执行了几个重载方法,最后走到newRequestQueue

public static RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes) {
    File cacheDir = new File(context.getCacheDir(), "volley");
    String userAgent = "volley/0";

    try {
        String packageName = context.getPackageName();
        PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
        userAgent = packageName + "/" + info.versionCode;
    } catch (NameNotFoundException var7) {
        ;
    }

    //这里进行了一个版本的判断 2.3之前用的是HTTPClient,2.3之后使用的是HttpURLConnection
    if (stack == null) {
        if (VERSION.SDK_INT >= 9) {
            stack = new HurlStack();
        } else {
            stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
        }
    }

    Network network = new BasicNetwork((HttpStack)stack);
    RequestQueue queue;
    if (maxDiskCacheBytes <= -1) {
        queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
    } else {
        queue = new RequestQueue(new DiskBasedCache(cacheDir, maxDiskCacheBytes), network);
    }

    queue.start();
    return queue;
}

在这里,我们看到了一个版本判断,是不是瞬间感觉有点熟悉,没错,我们前面说的,volley2.3之前用的是HTTPClient,2.3之后使用的是HttpURLConnection就是在这里进行判断的。接着看queue.start();

public void start() {
        this.stop();
        this.mCacheDispatcher = new CacheDispatcher(this.mCacheQueue, this.mNetworkQueue, this.mCache, this.mDelivery);
        this.mCacheDispatcher.start();

        for(int i = 0; i < this.mDispatchers.length; ++i) {
            NetworkDispatcher networkDispatcher = new NetworkDispatcher(this.mNetworkQueue, this.mNetwork, this.mCache, this.mDelivery);
            this.mDispatchers[i] = networkDispatcher;
            networkDispatcher.start();
        }

    }

mCacheDispatcher是缓存调度线程,NetworkDispatcher是网络调度线程,而这个this.mDispatchers.length系统默认的大小为4,也就是说,在这里总共启动了5个线程在后台运行。

好了,到这里,就可以了,看源码不要每一行都弄懂,不然,出不来了。到这里就拿到了这个RequestQueue对象。回过头来看前面使用的代码

//获取volley的请求对象
RequestQueue requestQueue = Volley.newRequestQueue(getApplicationContext());
StringRequest stringRequest = new StringRequest(StringRequest.Method.GET, "http://www.baidu.com", new Response.Listener<String>() {
    @Override
    public void onResponse(String s) {
        Log.d("MainActivity", "----->" + s);

    }
}, new Response.ErrorListener() {
    @Override
    public void onErrorResponse(VolleyError volleyError) {
        Log.d("MainActivity", "---volleyError-->" + volleyError);
    }
});
requestQueue.add(stringRequest);

我们拿到这个RequestQueue对象以后,然后就把这个请求通过add方法添加到队列中,我们看看这个add()方法是怎么执行的。

public <T> Request<T> add(Request<T> request) {
        request.setRequestQueue(this);
        Set var2 = this.mCurrentRequests;
        synchronized(this.mCurrentRequests) {
            this.mCurrentRequests.add(request);
        }

        request.setSequence(this.getSequenceNumber());
        request.addMarker("add-to-queue");
        if (!request.shouldCache()) { //如果不能缓存
            this.mNetworkQueue.add(request);
            return request;
        } else {
            Map var7 = this.mWaitingRequests;
            synchronized(this.mWaitingRequests) {
                String cacheKey = request.getCacheKey();
                if (this.mWaitingRequests.containsKey(cacheKey)) { //判断之前是否执行过,但是还没有返回结果
                    Queue<Request<?>> stagedRequests = (Queue)this.mWaitingRequests.get(cacheKey);
                    if (stagedRequests == null) {
                        stagedRequests = new LinkedList();
                    }

                    ((Queue)stagedRequests).add(request);
                    this.mWaitingRequests.put(cacheKey, stagedRequests);
                    if (VolleyLog.DEBUG) {
                        VolleyLog.v("Request for cacheKey=%s is in flight, putting on hold.", new Object[]{cacheKey});
                    }
                } else {
                //没有的话就将请求加入缓存队列mCacheQueue,同时加入mWaitingRequests中用来做下次同样请求来时的重复判断依据
                    this.mWaitingRequests.put(cacheKey, (Object)null);
                    this.mCacheQueue.add(request);
                }

                return request;
            }
        }
    }

从代码中可以看出,首先判断是否可以缓存,当然,默认是可以缓存的。如果不能缓存的话,则通过this.mNetworkQueue.add(request);将请求添加到网络请求队列中。如果可以缓存,则还会判断一次这个请求是否请求,如果执行过就就通过this.mWaitingRequests.put(cacheKey, stagedRequests);添加到mWaitingRequests队列,不在重复请求。否则就加入到缓存队列。

大体的流程是这样。现在我们看看缓存的,和网络的是怎么执行的。我们找到start()方法

public void start() {
        this.stop();
        this.mCacheDispatcher = new CacheDispatcher(this.mCacheQueue, this.mNetworkQueue, this.mCache, this.mDelivery);
        this.mCacheDispatcher.start();

        for(int i = 0; i < this.mDispatchers.length; ++i) {
            NetworkDispatcher networkDispatcher = new NetworkDispatcher(this.mNetworkQueue, this.mNetwork, this.mCache, this.mDelivery);
            this.mDispatchers[i] = networkDispatcher;
            networkDispatcher.start();
        }

    }

先看CacheDispatcher,找到run()方法

public void run() {
        if (DEBUG) {
            VolleyLog.v("start new dispatcher", new Object[0]);
        }

        Process.setThreadPriority(10);
        this.mCache.initialize();

        while(true) {
            while(true) {
                while(true) {
                    while(true) {
                        try {
                            while(true) {
                                final Request<?> request = (Request)this.mCacheQueue.take(); //从缓存队列中获取到一个请求
                                request.addMarker("cache-queue-take");
                                if (request.isCanceled()) { //判断请求是否取消,如果取消了,那就将该请求finish掉
                                    request.finish("cache-discard-canceled");
                                } else {
                                    Entry entry = this.mCache.get(request.getCacheKey());
                                    if (entry == null) {//如果从缓存中取出来的内容为空,则将请求加入到网络线程中再次请求
                                        request.addMarker("cache-miss");
                                        this.mNetworkQueue.put(request);
                                    } else if (entry.isExpired()) { //如果请求过期了,则将请求加入到网络线程中再次请求
                                        request.addMarker("cache-hit-expired");
                                        request.setCacheEntry(entry);
                                        this.mNetworkQueue.put(request);
                                    } else { //将数据回调到主线程
                                        request.addMarker("cache-hit");
                                        Response<?> response = request.parseNetworkResponse(new NetworkResponse(entry.data, entry.responseHeaders));
                                        request.addMarker("cache-hit-parsed");
                                        if (entry.refreshNeeded()) {
                                            request.addMarker("cache-hit-refresh-needed");
                                            request.setCacheEntry(entry);
                                            response.intermediate = true;
                                            this.mDelivery.postResponse(request, response, new Runnable() {
                                                public void run() {
                                                    try {
                                                        CacheDispatcher.this.mNetworkQueue.put(request);
                                                    } catch (InterruptedException var2) {
                                                        ;
                                                    }

                                                }
                                            });
                                        } else {
                                            this.mDelivery.postResponse(request, response);
                                        }
                                    }
                                }
                            }
                        } catch (InterruptedException var4) {
                            if (this.mQuit) {
                                return;
                            }
                        }
                    }
                }
            }
        }
    }

这里嵌套了几个循环,有点凌乱啊,但是慢慢分析的话,就会发现,其实很清晰。我在注释上面写了,这里就不重复了

我们在看看NetworkDispatcher,看看网络线程是怎么执行的。一样找到run()方法

public void run() {
        Process.setThreadPriority(10);

        while(true) {
            long startTimeMs;
            Request request;
            while(true) {
                startTimeMs = SystemClock.elapsedRealtime();

                try {
                    request = (Request)this.mQueue.take(); //获取到一个请求
                    break;
                } catch (InterruptedException var6) {
                    if (this.mQuit) {
                        return;
                    }
                }
            }

            try {
                request.addMarker("network-queue-take");
                if (request.isCanceled()) { //如果请求取消了,则将请求finish掉
                    request.finish("network-discard-cancelled");
                } else {//进行网络请求
                    this.addTrafficStatsTag(request);
                    NetworkResponse networkResponse = this.mNetwork.performRequest(request);
                    request.addMarker("network-http-complete");
                    if (networkResponse.notModified && request.hasHadResponseDelivered()) {
                        request.finish("not-modified");
                    } else {
                        Response<?> response = request.parseNetworkResponse(networkResponse);
                        request.addMarker("network-parse-complete");
                        if (request.shouldCache() && response.cacheEntry != null) {
                            this.mCache.put(request.getCacheKey(), response.cacheEntry);
                            request.addMarker("network-cache-written");
                        }

                        request.markDelivered();
                        this.mDelivery.postResponse(request, response);
                    }
                }
            } catch (VolleyError var7) {
                var7.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
                this.parseAndDeliverNetworkError(request, var7);
            } catch (Exception var8) {
                VolleyLog.e(var8, "Unhandled exception %s", new Object[]{var8.toString()});
                VolleyError volleyError = new VolleyError(var8);
                volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
                this.mDelivery.postError(request, volleyError);
            }
        }
    }

代码比较多,我们直接找到NetworkResponse networkResponse = this.mNetwork.performRequest(request);这句代码,这句代码就是请求网络的代码,最核心的。performRequest是一个接口,我们看看这个performRequest()方法。Network在最开始说版本判断的时候里面有一句代码Network network = new BasicNetwork((HttpStack)stack); 从这句代码,我们可以知道BasicNetwork才是最终实现网络请求的类,我们找到performRequest方法

public NetworkResponse performRequest(Request<?> request) throws VolleyError {
        long requestStart = SystemClock.elapsedRealtime();

        while(true) {
            HttpResponse httpResponse = null;
            byte[] responseContents = null;
            Map responseHeaders = Collections.emptyMap();

            try {
                Map<String, String> headers = new HashMap();
                this.addCacheHeaders(headers, request.getCacheEntry());
                httpResponse = this.mHttpStack.performRequest(request, headers);
                StatusLine statusLine = httpResponse.getStatusLine();
                int statusCode = statusLine.getStatusCode();
                responseHeaders = convertHeaders(httpResponse.getAllHeaders());
                if (statusCode == 304) {
                    Entry entry = request.getCacheEntry();
                    if (entry == null) {
                        return new NetworkResponse(304, (byte[])null, responseHeaders, true, SystemClock.elapsedRealtime() - requestStart);
                    }

                    entry.responseHeaders.putAll(responseHeaders);
                    return new NetworkResponse(304, entry.data, entry.responseHeaders, true, SystemClock.elapsedRealtime() - requestStart);
                }

                if (statusCode == 301 || statusCode == 302) {
                    String newUrl = (String)responseHeaders.get("Location");
                    request.setRedirectUrl(newUrl);
                }

                byte[] responseContents;
                if (httpResponse.getEntity() != null) {
                    responseContents = this.entityToBytes(httpResponse.getEntity());
                } else {
                    responseContents = new byte[0];
                }

                long requestLifetime = SystemClock.elapsedRealtime() - requestStart;
                this.logSlowRequests(requestLifetime, request, responseContents, statusLine);
                if (statusCode >= 200 && statusCode <= 299) {
                    return new NetworkResponse(statusCode, responseContents, responseHeaders, false, SystemClock.elapsedRealtime() - requestStart);
                }

                throw new IOException();
            } catch (SocketTimeoutException var12) {
                attemptRetryOnException("socket", request, new TimeoutError());
            } catch (ConnectTimeoutException var13) {
                attemptRetryOnException("connection", request, new TimeoutError());
            } catch (MalformedURLException var14) {
                throw new RuntimeException("Bad URL " + request.getUrl(), var14);
            } catch (IOException var15) {
                int statusCode = false;
                NetworkResponse networkResponse = null;
                if (httpResponse == null) {
                    throw new NoConnectionError(var15);
                }

                int statusCode = httpResponse.getStatusLine().getStatusCode();
                if (statusCode != 301 && statusCode != 302) {
                    VolleyLog.e("Unexpected response code %d for %s", new Object[]{statusCode, request.getUrl()});
                } else {
                    VolleyLog.e("Request at %s has been redirected to %s", new Object[]{request.getOriginUrl(), request.getUrl()});
                }

                if (responseContents == null) {
                    throw new NetworkError(networkResponse);
                }

                networkResponse = new NetworkResponse(statusCode, (byte[])responseContents, responseHeaders, false, SystemClock.elapsedRealtime() - requestStart);
                if (statusCode != 401 && statusCode != 403) {
                    if (statusCode != 301 && statusCode != 302) {
                        throw new ServerError(networkResponse);
                    }

                    attemptRetryOnException("redirect", request, new AuthFailureError(networkResponse));
                } else {
                    attemptRetryOnException("auth", request, new AuthFailureError(networkResponse));
                }
            }
        }
    }

代码比较多,但是大多数代码是判断状态返回码的,不需要理会。

我们直接看httpResponse = this.mHttpStack.performRequest(request, headers);这一句代码,HttpStack这个有没有很熟悉。没有??没关系我在复制一次代码

if (stack == null) {
    if (VERSION.SDK_INT >= 9) {
        stack = new HurlStack();
    } else {
        stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
    }
}

还是在这个版本判断这里,这里就是HurlStack就是真正的网络请求的类了,网络请求,就是写在这个类里面的。好了,volley整个流程大概就是这样了。现在大家回过头看最初的哪一张图,是不是明了很多。

以上就是解析Android框架之Volley源码的详细内容,更多关于Android框架之Volley源码的资料请关注我们其它相关文章!

(0)

相关推荐

  • Android使用Volley实现上传文件功能

    一个项目中用到的使用Volley上传头像文件的例子,供大家参考,具体内容如下 /** * Created by wangshihui on 2015/11/30. * 上传文件 * url:..... method:post 参数:file 接口给的参数:file 就是表单的key,传给mFilePartName; 这是个测试类,测试上传头像没有问题,适合只上传单个文件的场景 */ public class MultipartRequest extends Request<JSONObject>

  • Android框架Volley使用:ImageRequest请求实现图片加载

    首先我们在项目中导入这个框架: implementation 'com.mcxiaoke.volley:library:1.0.19' 在AndroidManifest文件当中添加网络权限: <uses-permission android:name="android.permission.INTERNET"/> 下面是我们的首页布局: 在这个布局当中我们将Volley框架的所有功能都做成了一个按钮,按下按钮之后就会在"显示结果"下面显示结果,显示结果下

  • Android使用Volley框架定制PostUploadRequest上传文件

    发现问题 项目中有发表动态的功能,该功能可以将文本和图片上传至服务器. Volley通过定制PostUploadRequest实现文件上传的功能,本文以一张图片上传为例. 数据格式 以下为项目中图片上传实例的数据格式 多张图片上传可通过添加--WebKitFormBoundary 内容实现 POST /CloudLife/user/social HTTP/1.1 Host: localhost Connection: keep-alive Cache-Control: max-age=0 Acc

  • Android框架Volley使用之Json请求实现

    首先我们在项目中导入这个框架: implementation 'com.mcxiaoke.volley:library:1.0.19' 在AndroidManifest文件当中添加网络权限: <uses-permission android:name="android.permission.INTERNET"/> 下面是我们的首页布局: 在这个布局当中我们将Volley框架的所有功能都做成了一个按钮,按下按钮之后就会在"显示结果"下面显示结果,显示结果下

  • Android中volley封装实践记录

    前言 在项目中一般使用使用volley方式如下,用起来给人一种很乱的感觉,于是一种盘它的想法油然而生. public void get() { String url = "https://tcc.taobao.com/cc/json/mobile_tel_segment.htm?tel=......"; StringRequest request = new StringRequest(Request.Method.GET, url, new Response.Listener<

  • Android框架Volley之利用Imageloader和NetWorkImageView加载图片的方法

    首先我们在项目中导入这个框架: implementation 'com.mcxiaoke.volley:library:1.0.19' 在AndroidManifest文件当中添加网络权限: <uses-permission android:name="android.permission.INTERNET"/> 下面是我们的首页布局: 在这个布局当中我们将Volley框架的所有功能都做成了一个按钮,按下按钮之后就会在"显示结果"下面显示结果,显示结果下

  • Android Volley扩展实现支持进度条的文件上传功能

    volley是一个轻量级的开源网络通信框架,开源的好处就是可以自由定制自己需要的jar包.volley里网络通信时android2.3以上用的HttpUrlConnection,2.3以下用的HttpClient,我做的改动只考虑了2.3以上,不支持2.3版本以下.HttpUrlConnection默认传输数据是将数据全部写到内存中再发送到服务端,Volley就是采用默认的方式,这样在上传大文件时很容易就out of memory,有一种解决办法是设置每次传输流的大小: 已知文件大小:conne

  • Android中volley封装实践记录(二)

    前言 关于android的volley封装之前写过一篇文章,见链接(https://www.jb51.net/article/155875.htm).这篇文章主要是换种方式进行封装,具体步骤如下所示. 步骤如下 1.创建Request,并设置相应的参数: public class CommonJsonObjectRequest extends JsonObjectRequest { private String TAG = this.getClass().getSimpleName(); /*

  • Android框架Volley使用之Post请求实现方法

    首先我们在项目中导入这个框架: implementation 'com.mcxiaoke.volley:library:1.0.19' 在AndroidManifest文件当中添加网络权限: <uses-permission android:name="android.permission.INTERNET"/> 下面是我们的首页布局: 在这个布局当中我们将Volley框架的所有功能都做成了一个按钮,按下按钮之后就会在"显示结果"下面显示结果,显示结果下

  • 解析Android框架之Volley源码

    Volley简单使用 我这里是以依赖架包的形式 ,大家也可以以gradle的形式进行依赖. 好了,接下来上代码了..... //获取volley的请求对象 RequestQueue requestQueue = Volley.newRequestQueue(getApplicationContext()); StringRequest stringRequest = new StringRequest(StringRequest.Method.GET, "http://www.baidu.com

  • 解析Android框架之OkHttp3源码

    OkHttp流程图 OkHttp基本使用 gradle依赖 implementation 'com.squareup.okhttp3:okhttp:3.11.0' implementation 'com.squareup.okio:okio:1.15.0' /** *这里拿get请求来 * 异步的get请求 */ public void okhttpAsyn() { //设置超时的时间 OkHttpClient.Builder builder = new OkHttpClient.Builder

  • Android文件存储SharedPreferences源码解析

    1.我们都知道SharedPreferences 是android可以用来存放key value的的文件. SharedPreferences sp = getSharedPreferences("fileName", Context.MODE_PRIVATE); SharedPreferences.Editor editor = sp.edit(); editor.putString("key","value"); editor.commit(

  • 前端框架arco table源码遇到的问题解析

    目录 前言 离谱的filter代码 疑问1: 打不全补丁 更大的问题 错误的继续 显而易见的问题 结尾 如何改进,有兴趣的同学可以去提pr 前言 先不说别的,上两个arco design table的bug.本来是写react table组件,然后看源码学习思路,结果看的我真的很想吐槽.(其他组件我在学习源码上受益匪浅,尤其是工程化arco-cli那部分,我自己尝试写的轮子也是受到很多启发,这个吐槽并不是真的有恶意,我对arco和腾讯的tdeisgn是有期待的,因为ant一家独大太久了,很期待新

  • Android Jetpack 组件LiveData源码解析

    目录 前言 基本使用 疑问 源码分析 Observer ObserverWrapper LifecycleBoundObserver MutableLiveData postValue setValue 问题答疑 LiveData 特性引出的问题 问题解决 最后 前言 本文来分析下 LiveData 的源码,以及其在实际开发中的一些问题. 基本使用 一般来说 LiveData 都会配合 ViewModel 使用,篇幅原因关于 ViewModel 的内容将在后续博客中分析,目前可以将 ViewMo

  • Volley源码之使用方式和使用场景详解

    概述 Volley是Google在2013年推出的一个网络库,用于解决复杂网络环境下网络请求问题.刚推出的时候是非常火的,现在该项目的变动已经很少了.项目库地址为https://android.googlesource.com/platform/frameworks/volley 通过提交历史可以看到,最后一次修改距离今天已经有一段时间了.而volley包的release版本也已经很久没有更新了. author JeffDavidson<jpd@google.com> SunMar1316:3

  • 解析从小程序开发者工具源码看原理实现

    如何查看小程序开发者工具源码 下面我们通过微信小程序开发者工具的源码来说说小程序的底层实现原理.以开发者工具版本号State v1.02.1904090的源码来窥探小程序的实现思路.如何查看微信源码,对于mac用户而言,查看微信小程序开发者工具的包内容,然后进入Contents/Resources/app.nw/js/core/index.js,注释掉如下代码就可以查看开发者工具渲染后的代码. // 打开 inspect 窗口 if (nw.App.argv.indexOf('inspect')

  • 实时获取股票数据的android app应用程序源码分享

    最近学习Android应用开发,不知道写一个什么样的程序来练练手,正好最近股票很火,就一个App来实时获取股票数据,取名为Mystock.使用开发工具Android Studio,需要从Android官网下载,下载地址:http://developer.android.com/sdk/index.html.不幸的是Android是Google公司的,任何和Google公司相关的在国内都无法直接访问,只能通过VPN访问. 下图为Android Studio打开一个工程的截图: 下面按步介绍Myst

  • Android消息循环机制源码深入理解

    Android消息循环机制源码 前言: 搞Android的不懂Handler消息循环机制,都不好意思说自己是Android工程师.面试的时候一般也都会问这个知识点,但是我相信大多数码农肯定是没有看过相关源码的,顶多也就是网上搜搜,看看别人的文章介绍.学姐不想把那个万能的关系图拿出来讨论. 近来找了一些关于android线程间通信的资料,整理学习了一下,并制作了一个简单的例子. andriod提供了 Handler 和 Looper 来满足线程间的通信.例如一个子线程从网络上下载了一副图片,当它下

  • Android实现屏幕锁定源码详解

    最近有朋友问屏幕锁定的问题,自己也在学习,网上找了下也没太详细的例子,看的资料书上也没有有关屏幕锁定程序的介绍,下个小决心,自己照着官方文档学习下,现在做好了,废话不多说,先发下截图,看下效果,需要注意的地方会加注释,有问题的朋友可以直接留言,我们共同学习交流,共同提高进步!直接看效果图: 一:未设置密码时进入系统设置的效果图如下: 二:设置密码方式预览: 三:密码解密效果图 四:九宫格解密时的效果图 下面来简单的看下源码吧,此处讲下,这个小DEMO也是临时学习下的,有讲的不明白的地方请朋友直接

随机推荐