Volley解析(一)-- 源码

本文详细解析了Volley网络库的使用方式、网络请求流程、网络分发器和缓存分发器的工作逻辑。从创建请求队列到执行网络请求,再到缓存处理,深入探讨了Volley内部实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

涉及到的知识点:

  1. Volley网络请求的流程
  2. 网络分发器逻辑
  3. 缓存分发器逻辑

准备

在正式开始分析Volley源码逻辑之前,有两件事需要搞明白:

  1. Volley是怎么使用的?
  2. 请求的流程是怎样的?

我们先从基本的使用开始吧。

Volley的使用方式

我们以通过点击Button加载图片为例,来说明一下Volley的使用。其实很简单,就是在Activity的布局里面放置一个Button,监听它的点击事件,点击逻辑如下:

//实例化消息队列
RequestQueue requestQueue = Volley.newRequestQueue(this);

//实例化图片请求
ImageRequest imageRequest = new ImageRequest("http://wanandroid.com/resources/image/pc/logo.png",
                new Response.Listener<Bitmap>() {
                    @Override
                    public void onResponse(Bitmap response) {
                        mIvShowDownloadImage.setImageBitmap(response);
                    }
                }, 0, 0, Bitmap.Config.RGB_565,
                new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                        mIvShowDownloadImage.setImageResource(R.mipmap.ic_launcher);
                    }
                });

//设置不缓存(后面会讲到缓存逻辑)
imageRequest.setShouldCache(false);
//将请求添加到缓存队列中,开始执行
requestQueue.add(imageRequest);

上面逻辑的结果如下:

Volley使用范例效果展示

Volley网络请求流程

学习Volley的网络请求流程,我们上一张官方的原理图吧,然后简单说明一下大概的流程,在后面我们会详细分析。

Volley官方流程图

根据上图,结合上一小节我们来大致的说明一下网络请求的流程:

  1. 构建网络请求实体类对象(Request抽象类实现类对象),将其添加到请求队列中(默认会添加到缓存队列中)
  2. 在默认情况下,会去判断缓存是否命中(当前请求的缓存key和已经缓存的缓存结果的key是否相同),命中(存在相同缓存key)则直接从缓存中取请求结果返回给请求。如果没有命中将请求添加到网络请求队列中
  3. 网络请求队列执行真正的网络请求,然后解析响应,写入缓存,回调结果监听等

说实话感觉并没有什么内容,但是之所以要分析源码,就是为了学习思想,学习架构,好吧装了一波逼。。。下面开始正文。

我们从RequestQueue requestQueue = Volley.newRequestQueue(this);开始追踪源码,可以发现它会调用重载的newRequestQueue函数,我们去看一下重载的函数做了什么:

public static RequestQueue newRequestQueue(Context context, BaseHttpStack stack) {
        BasicNetwork network;
        if (stack == null) {
            if (Build.VERSION.SDK_INT >= 9) {
                network = new BasicNetwork(new HurlStack());
            } else {
                String userAgent = "volley/0";
                try {
                    String packageName = context.getPackageName();
                    PackageInfo info =
                            context.getPackageManager().getPackageInfo(packageName, /* flags= */ 0);
                    userAgent = packageName + "/" + info.versionCode;
                } catch (NameNotFoundException e) {
                }

                network =
                        new BasicNetwork(
                                new HttpClientStack(AndroidHttpClient.newInstance(userAgent)));
            }
        } else {
            network = new BasicNetwork(stack);
        }

        return newRequestQueue(context, network);
    }

看着是不少,实际上就是实例化了一个network参数,然后再次调用另一个重载的newRequestQueue函数。这里的话有两点:

第一:network参数,是一个BasicNetwork的实例,它是接口Network的实现类,是执行网络请求的执行类;

第二:重载的newRequestQueue函数,我们点击进去看一下,它里面做了什么:

private static RequestQueue newRequestQueue(Context context, Network network) {
        //初始化缓存文件
        File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);
        //实例化请求队列
        RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
        //队列开始分发请求
        queue.start();
        return queue;
    }

可以发现其实一共就做了三个操作,操作一:创建缓存文件;操作二:调用RequestQueue的构造函数,构建了一个请求队列;操作三:开始分发请求。构建RequestQueue的话就是初始化了一些参数,重点在于start函数,我们去看一下:

/**
 * 分发当前队列的请求
 */
public void start() {
    //确保当前(其实是之前的,因为我们要使用新的,所以要把之前的全部清空)正在运行的所有分发器全部退出(不论是网络请求的,还是缓存的)
    stop();
    // 创建新的缓存请求分发器,并开始(分发器其实就是线程)
    mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);
    //调用线程的start方法
    mCacheDispatcher.start();

    // 创建新的网络请求分发器,并开始执行(网络请求分发器默认是4个实例)
    for (int i = 0; i < mDispatchers.length; i++) {
        NetworkDispatcher networkDispatcher =
                new NetworkDispatcher(mNetworkQueue, mNetwork, mCache, mDelivery);
        mDispatchers[i] = networkDispatcher;
        networkDispatcher.start();
    }
}

可以发现,这里面主要就是初始化缓存分发器和网络分发器,并调用它们的start方法,那么这些分发器到底是什么鬼呢?我们一个个来看,先从网络分发器开始吧。

网络分发器

点击进入NetworkDispatcher看一下源码,发现原来它的本质就是一条线程啊,重写了run方法,并且在run写了一个死循环,不断的执行processRequest函数,具体源码如下:

public class NetworkDispatcher extends Thread {
   
   

    /** The queue of requests to service. */
    private final BlockingQueue<Request<?>> mQueue;
    /** The network interface for processing requests. */
    private final Network mNetwork;
    /** The cache to write to. */
    private final Cache mCache;
    /** For posting responses and errors. */
    private final ResponseDelivery mDelivery;
    /** Used for telling us to die. */
    private volatile boolean mQuit = false;

    public NetworkDispatcher(
            BlockingQueue<Request<?>> queue,
            Network network,
            Cache cache,
            ResponseDelivery delivery) {
        mQueue = queue;
        mNetwork = network;
        mCache = cache;
        mDelivery = delivery;
    }

    /**
     * Forces this dispatcher to quit immediately. If any requests are still in the queue, they are
     * not guaranteed to be processed.
     */
    public void quit() {
        mQuit = true;
        interrupt();
    }

    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
    private void addTrafficStatsTag(Request<?> request) {
        // Tag the request (if API >= 14)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
            TrafficStats.setThreadStatsTag(request.getTrafficStatsTag());
        }
    }

    @Override
    public void run() {
        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
        //跟轮训器一样,不断调用执行请求的函数
        while (true) {
            try {
                //执行请求
                processRequest();
            } catch (InterruptedException e) {
                // We may have been interrupted because it was time to quit.
                if (mQuit) {
                    return;
                }
            }
        }
    }

    private void proc
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值