Android知识Android技术知识Android开发

Volley源码解析

2016-10-30  本文已影响102人  cgzysan

Volley介绍

Volley 是 Google 在 2013 Google I/O 大会上发布推出的 Android 异步网络请求框架和图片加载框架,其最明显的一个优点就是特别适合数据量不大但是通信频繁的场景,最明显的缺点就是大数据传输表现的很糟糕。(适合于数据量小,通信频繁的网络操作)

Volley提供了以下的便利功能

newRequestQueue的使用

Volley的用法很简单,发起一条HTTP GET请求,然后接收HTTP响应。首先需要获取到一个RequestQueue对象,可以调用如下方法获取到:

RequestQueue newQueue = Volley.newRequestQueue(context);

这里拿到的RequestQueue是一个请求队列对象,它可以缓存所有的HTTP请求,然后按照一定的算法并发地发出这些请求。

RequestQueue内部的设计就是非常合适高并发的,因此我们不必为每一次HTTP请求都创建一个RequestQueue对象,这是非常浪费资源的,基本上在每一个需要和网络交互的Activity中创建一个RequestQueue对象就足够了。

Request的使用

Request是请求的基类,拥有以下子类:

在基类中定义了一个内部接口类 Method 分别定义了集中常见的请求方式

public interface Method {
    int DEPRECATED_GET_OR_POST = -1;
    int GET = 0;
    int POST = 1;
    int PUT = 2;
    int DELETE = 3;
    int PATCH = 4;
}

同时还定义了一个枚举 Priority 定义了一些优先级的常量

public static enum Priority {
    LOW,
    NORMAL,
    HIGH,
    IMMEDIATE;

    private Priority() {
    }
}

StringRequestd的使用

StringRequest的构造函数需要传入四个参数:

public StringRequest(int method, String url, Listener<String> listener, ErrorListener errorListener) {
    super(method, url, errorListener);
    this.mListener = listener;
}

将这个StringRequest对象添加到RequestQueue里面就可以了。使用Volley时,可以从任何线程开始请求,但响应始终传递到了主线程上。
以下是阅读Android Developer文档中的VolleyDemo:

final TextView mTextView = (TextView) findViewById(R.id.text);
...

// Instantiate the RequestQueue.
RequestQueue queue = Volley.newRequestQueue(this);
String url ="http://www.google.com";

// Request a string response from the provided URL.
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
            new Response.Listener() {
    @Override
    public void onResponse(String response) {
        // Display the first 500 characters of the response string.
        mTextView.setText("Response is: "+ response.substring(0,500));
    }
}, new Response.ErrorListener() {
    @Override
    public void onErrorResponse(VolleyError error) {
        mTextView.setText("That didn't work!");
    }
});
// Add the request to the RequestQueue.
queue.add(stringRequest);

以上就用Volley发起了一个简单的HTTP 的 GET 请求。

Volley发出Request

Volley发出网络请求,阻塞I/O和解析数据都是在子线程中完成的,您可以在任何线程添加网络请求,但是响应始终都是传递到主线程上。
分析一下 Android Developer 上的这幅图:

volley-request.png
BasicNetwork network1 = new BasicNetwork((HttpStack)stack);//将在后文提到
RequestQueue queue1 = new RequestQueue(new DiskBasedCache(cacheDir), network1);
queue1.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();
    }
}

没错,它逐一开启了缓存调度线程和所有的网络调度线程

取消一个Request

要取消一个请求,调用cancel()即可。一旦取消,Volley保证你的响应处理程序将永远不会被调用。这意味着在实践中,你可以取消所有待定的请求在你Activity的onStop()方法中,你不必乱抛垃圾的响应处理程序或者检查getActivity() == NULL,无论onSaveInstanceState()是否已经被调用。

你发出去的请求必须要自己保证是可控的,在这里还有一个更简单的方法:你可以标记发送的每个请求对象,然后你可以使用这个标签来提供请求取消的范围。

下面是一个使用字符串标签的例子:

  1. 定义您的标签同时将其添加到Request中
    public static final String TAG = "MyTag";
    StringRequest stringRequest; // Assume this exists.
    RequestQueue mRequestQueue; // Assume this exists.

     // Set the tag on the request.
     stringRequest.setTag(TAG);
     
     // Add the request to the RequestQueue.
     mRequestQueue.add(stringRequest);
    
  2. 在您的Activity的 onStop() 方法中,取消所有被标记的Request

     @Override
     protected void onStop () {
         super.onStop();
         if (mRequestQueue != null) {
             mRequestQueue.cancelAll(TAG);
         }
     }
    

取消请求时要小心。如果你是根据你的响应处理程序来推进一个状态或启动另一个进程,你需要考虑到这个。同样,响应处理程序将不会被调用。

BasicNetwork

现在我们来说说 BasicNetwork,前文在讲 RequestQueue 的时候有所提到,其中 BasicNetwork 是创建 RequestQueue 对象时当中的一个参数

HttpStack接口

HttpStack接口中也只有一个方法HttpResponse performRequest(Request<?> var1, Map<String, String> var2) throws IOException, AuthFailureError;
在前文我们提到了HttpStack的两个实现类 HttpClientStack 和 HurlStack,在实现的具体方法中真正进行了网络请求。

Request的parseNetworkResponse方法

以上步骤,在NetworkDispatcher中收到了NetworkResponse这个返回值后又会调用Request的parseNetworkResponse()方法来解析NetworkResponse中的数据,同时将数据写入到缓存,这个方法的实现是交给Request的子类来完成的,因为不同种类的Request解析的方式也肯定不同。

ResponseDelivery接口

在获取了解析后的数据之后,NetworkDispatcher的run()方法最后调用了this.mDelivery.postResponse(request, response);将数据post到主线程(UI线程),其中的 mDelivery 就是 ResponseDelivery接口的具体实现类 ExecutorDelivery对象,具体的方法如下:

@Override
public void postResponse(Request<?> request, Response<?> response, Runnable runnable) {
    request.markDelivered();
    request.addMarker("post-response");
    mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable));
}

ExecutorDelivery 的构造方法如下:

public ExecutorDelivery(final Handler handler) {
    this.mResponsePoster = new Executor() {
        public void execute(Runnable command) {
            handler.post(command);
        }
    };
}

在创建其实例的时候传入了 RequestQueue 实例的 mDelivery :

NetworkDispatcher networkDispatcher = new NetworkDispatcher(this.mNetworkQueue, this.mNetwork, this.mCache, this.mDelivery);

而 mDelivery 就是创建 RequestQueue 时创建的主线程Handler:

public RequestQueue(Cache cache, Network network, int threadPoolSize) {
    this(cache, network, threadPoolSize, new ExecutorDelivery(new Handler(Looper.getMainLooper())));
}

如此就保证了 ExecutorDelivery 对象中的 run() 方法在主线程中运行。

而在 run() 方法中最核心的代码就是:

if(this.mResponse.isSuccess()) {
    this.mRequest.deliverResponse(this.mResponse.result);
} else {
    this.mRequest.deliverError(this.mResponse.error);
}

调用了Request的 deliverResponse(this.mResponse.result)mRequest.deliverError(this.mResponse.error) 方法,其中就调用了需要重写的实现Listener接口方法,将反馈发送到回调到UI线程。

这是后来想起加的一张NetworkDispatcher的工作流程图:

NetworkDispatcher.png

有什么不对还请指出,谢谢指教。

上一篇下一篇

猜你喜欢

热点阅读