Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android:Volley源碼解析

Android:Volley源碼解析

編輯:關於Android編程

簡單實例

Volley是一個封裝HttpUrlConnection和HttpClient的網絡通信框架,集AsyncHttpClient和Universal-Image-Loader的優點於了一身,既可以像AsyncHttpClient一樣非常簡單地進行HTTP通信,也可以像Universal-Image-Loader一樣輕松加載並緩存下載的圖片。Volley在性能方面也進行了大幅度的調整,它的設計目標就是進行數據量不大,但通信頻繁的網絡操作,而對於大數據量的網絡操作,比如說下載文件等,Volley的表現就會比較糟糕。從下面這個簡單的實例來研究一下源碼。

RequestQueue mQueue = Volley.newRequestQueue(MainActivity.this);
StringRequest stringRequest = new StringRequest(http://www.baidu.com, new Response.Listener() {
    @Override
    public void onResponse(String s) {
        tv.setText(s);
    }
}, new Response.ErrorListener() {
    @Override
    public void onErrorResponse(VolleyError volleyError) {

    }
});
mQueue.add(stringRequest);

流程

1、以靜態工廠形式實例化一個RequestQueue對象

RequestQueue mQueue = Volley.newRequestQueue(MainActivity.this);

首先看一下RequestQueue這個類:
public class RequestQueue {
    private AtomicInteger mSequenceGenerator;
    private final Map> mWaitingRequests;
    private final Set mCurrentRequests;
    private final PriorityBlockingQueue mCacheQueue;
    private final PriorityBlockingQueue mNetworkQueue;
    private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4;
    private final Cache mCache;
    private final Network mNetwork;
    private final ResponseDelivery mDelivery;
    private NetworkDispatcher[] mDispatchers;
    private CacheDispatcher mCacheDispatcher;

    public RequestQueue(Cache cache, Network network, int threadPoolSize, ResponseDelivery delivery) {
        this.mSequenceGenerator = new AtomicInteger();
        this.mWaitingRequests = new HashMap();
        this.mCurrentRequests = new HashSet();
        this.mCacheQueue = new PriorityBlockingQueue();
        this.mNetworkQueue = new PriorityBlockingQueue();
        this.mCache = cache;
        this.mNetwork = network;
        this.mDispatchers = new NetworkDispatcher[threadPoolSize];
        this.mDelivery = delivery;
    }

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

    public RequestQueue(Cache cache, Network network) {
        this(cache, network, 4);
    }
    ...
}

從構造函數可知,mWaitingRequests、mCurrentRequests、mCacheQueue、mNetworkQueue是以組合形式實例化,後兩者是阻塞隊列;而mCache、mNetwork是以聚合形式注入;mDelivery默認也是組合形式new ExecutorDelivery(new Handler(Looper.getMainLooper())))實例化。

newRequestQueue方法:
public static RequestQueue newRequestQueue(Context context) {
        return newRequestQueue(context, (HttpStack)null);
    }
 public static RequestQueue newRequestQueue(Context context, HttpStack stack) {
        File cacheDir = new File(context.getCacheDir(), volley);
        String userAgent = volley/0;

        try {
            String network = context.getPackageName();
            PackageInfo queue = context.getPackageManager().getPackageInfo(network, 0);
            userAgent = network + / + queue.versionCode;
        } catch (NameNotFoundException var6) {
            ;
        }

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

        BasicNetwork network1 = new BasicNetwork((HttpStack)stack);
        RequestQueue queue1 = new RequestQueue(new DiskBasedCache(cacheDir), network1);
        queue1.start();
        return queue1;
    }

結合RequestQueue類可知,實例化的RequestQueue對象,注入了new DiskBasedCache(cacheDir)network1,緩存方式默認是磁盤緩存,NetWork對象會根據系統版本,選用不同的Http通信方式。

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();
        }

    }

CacheDispatcher和NetworkDispatcher都是繼承Thread類,所以這個方法生成一條緩存分發線程,和四條網絡線程。

CacheDispatcher類繼承Thread類,所有參數都是聚合形式注入,看下關鍵的run()方法,由於代碼較長,這裡不貼了,分段分析下幾個比較重要的方法
while(true){
    ...
    Request e = (Request)this.mCacheQueue.take();
    ...
}

首先任務是一個死循環,由於mCacheQueue是個阻塞隊列,所以將不斷地從阻塞隊列讀取Request


 Entry entry = this.mCache.get(e.getCacheKey());
                                    if(entry == null) {
                                        e.addMarker(cache-miss);
                                        this.mNetworkQueue.put(e);
                                    } else if(entry.isExpired()) {
                                        e.addMarker(cache-hit-expired);
                                        e.setCacheEntry(entry);
                                        this.mNetworkQueue.put(e);
                                    } else {
                                        e.addMarker(cache-hit);
                                        Response response = e.parseNetworkResponse(new NetworkResponse(entry.data, entry.responseHeaders));
                                        ...
                                        }

判斷請求是否有緩存,如果沒有或者緩存已經過期,將請求放到網絡隊列裡面。否則找到緩存,則進行下面的操作。


Response response = e.parseNetworkResponse(new NetworkResponse(entry.data, entry.responseHeaders));

parseNetworkResponse是Request類的抽象方法,我們進去StringRequest看下:

protected Response parseNetworkResponse(NetworkResponse response) {
        String parsed;
        try {
            parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
        } catch (UnsupportedEncodingException var4) {
            parsed = new String(response.data);
        }

        return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
    }

可看作是對網絡下載的數據進行解析處理,然後返回。


this.mDelivery.postResponse(e, response);

最後進行這一步,mDelivery是在RequestQueue裡面實例化後注入CacheDispatcher的,具體的實例化對象:new ExecutorDelivery(new Handler(Looper.getMainLooper()))。看下ExecutorDelivery類,找到postResponse方法。

    public void postResponse(Request request, Response response) {
        this.postResponse(request, response, (Runnable)null);
    }

    public void postResponse(Request request, Response response, Runnable runnable) {
    ...
        this.mResponsePoster.execute(new ExecutorDelivery.ResponseDeliveryRunnable(request, response, runnable));
    }

繼續往下看

private class ResponseDeliveryRunnable implements Runnable {
    ...
    run(){
        ...
        if(this.mResponse.isSuccess()) {
                    this.mRequest.deliverResponse(this.mResponse.result);
                } 
        ...
    }
    ...
}

deliverResponse方法同樣是Request類的抽象方法,我們進去StringRequest看下

    protected void deliverResponse(String response) {
        this.mListener.onResponse(response);
    }

就一句回調


NetworkDispatcher類同樣繼承Thread類,其分析過程和CacheDispatcher差不多,重要的同樣是以下幾步:

1、從網絡阻塞隊列讀取請求,request = (Request)this.mQueue.take();
2、網絡下載,NetworkResponse e = this.mNetwork.performRequest(request);(如果是CacheDispatcher這一步就是緩存判斷)
3、處理下載後的數據,Response response = request.parseNetworkResponse(e);
3、對處理後的數據進行回調,this.mDelivery.postResponse(e, response)。


2、實例化一個Request對象

StringRequest stringRequest = new StringRequest (url,listener,errorListener);

public class StringRequest extends Request {
    private final Listener mListener;

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

    public StringRequest(String url, Listener listener, ErrorListener errorListener) {
        this(0, url, listener, errorListener);
    }

    protected void deliverResponse(String response) {
        this.mListener.onResponse(response);
    }

    protected Response parseNetworkResponse(NetworkResponse response) {
        String parsed;
        try {
            parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
        } catch (UnsupportedEncodingException var4) {
            parsed = new String(response.data);
        }

        return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
    }
}

由第一個分析步驟可以知道,這個Request主要就是進行兩個操作,也就是重寫兩個方法。

protected abstract Response parseNetworkResponse(NetworkResponse var1);對下載後的數據進行解析處理; protected abstract void deliverResponse(T var1);最後回調操作這個數據的方法。

所以構造函數僅需下載地址和回調操作的方法。


3、調用queue.add()方法

 if(!request.shouldCache()) {
            this.mNetworkQueue.add(request);
            return request;
        } 

如果不需要緩存就直接添加到網絡隊列裡面,Request有個比較重要的布爾字段mShouldCache,默認是用來判斷是否要進行磁盤緩存的。


this.mCacheQueue.add(request);

否則將其添加到緩存隊列,這個方法上面也會進行一些當前隊列和等待隊列的防重復的操作。


小結

這裡寫圖片描述

框架部分:
1、實例化一個RequestQueue對象,開啟一條緩存線程和默認的四條網絡線程,線程不斷地從緩存阻塞隊列和網絡阻塞隊列裡面讀取請求;
2、如果緩存線程從緩存隊列裡面讀取的請求已經緩存過,則解析數據回調操作方法,否則將其添加到網絡隊列;
3、如果緩存線程從緩存隊列裡面讀取的請求沒有緩存過,則添加到網絡隊列。
4、網絡線程從網絡阻塞隊列不斷讀取請求,讀到請求後則由封裝好的HttpStack對象進行網絡下載處理、下載後回調對數據處理的方法,處理後回調操作數據的方法。

客戶部分:
1、實例化一個請求對象,在請求對象裡面重寫處理網絡下載後的數據的方法,和操作處理後的數據的方法。
2、將請求對象添加到請求隊列,請求需要緩存則會被添加到分配到緩存隊列,不需要則被添加到網絡隊列。


之前看過一個問題,說框架和庫有什麼不同,高人答曰:框架是他調用你代碼,庫是你調用他代碼。優秀的框架拓展性是如此之強,雖然自己遠沒那個能力,不過也算開了眼界!

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved