Android_开源框架_Volley(Google IO 2013)源代码及内部实现分析

来源:互联网 发布:跑跑辅助源码猴岛 编辑:程序博客网 时间:2024/06/15 01:13
本博文为子墨原创,转载请注明出处!
http://blog.csdn.net/zimo2013/article/details/16971253

由于博主的水平有限,如有误,请您帮助指正,共同学习,共同进步!
供初学者更好的理解和管理Volley!
(1).Android_开源框架_Volley(Google IO 2013)源代码及内部实现分析
(2).Android_开源框架_Volley实例


1.Volley概述

在项目开发过程中,博主曾写过大量的访问网络重复代码,特别是ListView adapter很难避免getView()方法不被重复调用,如果ImageView不利用缓存机制,那么网络的负荷就会更大!曾将访问网络代码和缓存封装起来使用,但是中间仍存在不少瑕疵!今年的Google I/O 2013上,Volley发布了!Volley是Android平台上的网络通信库,能使网络通信更快,更简单,更健壮


Volley特别适合数据量不大但是通信频繁的场景,现在android提供的源码已经包含Volley,以后在项目中,可以根据需求引入Volley jar文件!

2.Volley源码分析

(1).Volley.java

Volley.newRequestQueue()方法在一个app最好执行一次,可以使用单例设计模式或者在application完成初始化,具体原因请查看代码分析

/** * @author zimo2013 * @see http://blog.csdn.net/zimo2013 */public static RequestQueue newRequestQueue(Context context, HttpStack stack) {    File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);    String userAgent = "volley/0";    try {        String packageName = context.getPackageName();        PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);        userAgent = packageName + "/" + info.versionCode;    } catch (NameNotFoundException e) {    }    if (stack == null) {        if (Build.VERSION.SDK_INT >= 9) {            stack = new HurlStack();        } else {            stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));        }    }    Network network = new BasicNetwork(stack);    //cacheDir 缓存路径 /data/data/<pkg name>/cache/<name>    RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);    queue.start();    /*     * 实例化一个RequestQueue,其中start()主要完成相关工作线程的开启,     * 比如开启缓存线程CacheDispatcher先完成缓存文件的扫描, 还包括开启多个NetworkDispatcher访问网络线程,     * 该多个网络线程将从 同一个 网络阻塞队列中读取消息     *      * 此处可见,start()已经开启,所有我们不用手动的去调用该方法,在start()方法中如果存在工作线程应该首先终止,并重新实例化工作线程并开启     * 在访问网络很频繁,而又重复调用start(),势必会导致性能的消耗;但是如果在访问网络很少时,调用stop()方法,停止多个线程,然后调用start(),反而又可以提高性能,具体可折中选择     */    return queue;}

(2).RequestQueue.java

/** * RequestQueue类存在2个非常重要的PriorityBlockingQueue类型的成员字段mCacheQueue mNetworkQueue ,该PriorityBlockingQueue为java1.5并发库提供的新类 * 其中有几个重要的方法,比如take()为从队列中取得对象,如果队列不存在对象,将会被阻塞,直到队列中存在有对象,类似于Looper.loop() *  * 实例化一个request对象,调用RequestQueue.add(request),该request如果不允许被缓存,将会被添加至mNetworkQueue队列中,待多个NetworkDispatcher线程take()取出对象 * 如果该request可以被缓存,该request将会被添加至mCacheQueue队列中,待mCacheDispatcher线程从mCacheQueue.take()取出对象, * 如果该request在mCache中不存在匹配的缓存时,该request将会被移交添加至mNetworkQueue队列中,待网络访问完成后,将关键头信息添加至mCache缓存中去! *  * @author zimo2013 * @see http://blog.csdn.net/zimo2013 */public void start() {    stop();        mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);    mCacheDispatcher.start();    // Create network dispatchers (and corresponding threads) up to the pool size.    for (int i = 0; i < mDispatchers.length; i++) {        NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,                mCache, mDelivery);        mDispatchers[i] = networkDispatcher;        networkDispatcher.start();    }}

 (3).CacheDispatcher.java

/** * @author zimo2013 * @see http://blog.csdn.net/zimo2013 */@Overridepublic void run() {    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);    //缓存初始化,会遍历整个缓存文件夹    mCache.initialize();    {    //执行代码    /*if (!mRootDirectory.exists()) {            if (!mRootDirectory.mkdirs()) {                VolleyLog.e("Unable to create cache dir %s", mRootDirectory.getAbsolutePath());            }            return;        }        File[] files = mRootDirectory.listFiles();        if (files == null) {            return;        }        for (File file : files) {            FileInputStream fis = null;            try {                fis = new FileInputStream(file);                CacheHeader entry = CacheHeader.readHeader(fis);                entry.size = file.length();                putEntry(entry.key, entry);            } catch (IOException e) {                if (file != null) {                   file.delete();                }            } finally {                try {                    if (fis != null) {                        fis.close();                    }                } catch (IOException ignored) { }            }        }*/    }    while (true) {        try {        //该方法可能会被阻塞            final Request request = mCacheQueue.take();            Cache.Entry entry = mCache.get(request.getCacheKey());            if (entry == null) {            //缓存不存在,则将该request添加至网络队列中                mNetworkQueue.put(request);                continue;            }            //是否已经过期            if (entry.isExpired()) {                request.setCacheEntry(entry);                mNetworkQueue.put(request);                continue;            }            Response<?> response = request.parseNetworkResponse(                    new NetworkResponse(entry.data, entry.responseHeaders));            //存在缓存,执行相关操作        } catch (InterruptedException e) {        }    }}

(4).NetworkDispatcher.java

/** * @author zimo2013 * @see http://blog.csdn.net/zimo2013 */@Overridepublic void run() {    Request request;    while (true) {        try {        //可能会被            request = mQueue.take();        } catch (InterruptedException e) {            // We may have been interrupted because it was time to quit.            if (mQuit) {                return;            }            continue;        }        try {                //访问网络,得到数据            NetworkResponse networkResponse = mNetwork.performRequest(request);            if (networkResponse.notModified && request.hasHadResponseDelivered()) {                request.finish("not-modified");                continue;            }            // Parse the response here on the worker thread.            Response<?> response = request.parseNetworkResponse(networkResponse);            // 写入缓存            if (request.shouldCache() && response.cacheEntry != null) {                mCache.put(request.getCacheKey(), response.cacheEntry);                request.addMarker("network-cache-written");            }            // Post the response back.            request.markDelivered();            mDelivery.postResponse(request, response);        } catch (VolleyError volleyError) {            parseAndDeliverNetworkError(request, volleyError);        } catch (Exception e) {            VolleyLog.e(e, "Unhandled exception %s", e.toString());            mDelivery.postError(request, new VolleyError(e));        }    }}

(5).StringRequest.java

其中在parseNetworkResponse()中,完成将byte[]到String的转化,可能会出现字符乱码,HttpHeaderParser.parseCharset(response.headers)方法在尚未指定是返回为ISO-8859-1,可以修改为utf-8
public class StringRequest extends Request<String> {    private final Listener<String> mListener;    /**     * Creates a new request with the given method.     *     * @param method the request {@link Method} to use     * @param url URL to fetch the string at     * @param listener Listener to receive the String response     * @param errorListener Error listener, or null to ignore errors     */    public StringRequest(int method, String url, Listener<String> listener,            ErrorListener errorListener) {        super(method, url, errorListener);        mListener = listener;    }    public StringRequest(String url, Listener<String> listener, ErrorListener errorListener) {        this(Method.GET, url, listener, errorListener);    }    @Override    protected void deliverResponse(String response) {        mListener.onResponse(response);    }    @Override    protected Response<String> parseNetworkResponse(NetworkResponse response) {        String parsed;        try {        //将data字节数据转化为String对象            parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));        } catch (UnsupportedEncodingException e) {            parsed = new String(response.data);        }        //返回Response对象,其中该对象包含访问相关数据        return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));    }}

(6).ImageLoader.java

/** * @author zimo2013 * @see http://blog.csdn.net/zimo2013 */public ImageContainer get(String requestUrl, ImageListener imageListener,        int maxWidth, int maxHeight) {    throwIfNotOnMainThread();    final String cacheKey = getCacheKey(requestUrl, maxWidth, maxHeight);    //从mCache得到bitmap对象,因此可以覆写ImageCache,完成图片的三级缓存,即在原有的LruCache添加一个软引用缓存    Bitmap cachedBitmap = mCache.getBitmap(cacheKey);    if (cachedBitmap != null) {    //得到缓存对象        ImageContainer container = new ImageContainer(cachedBitmap, requestUrl, null, null);        imageListener.onResponse(container, true);        return container;    }    ImageContainer imageContainer =            new ImageContainer(null, requestUrl, cacheKey, imageListener);    // 首先更新该view,其指定了defaultImage    imageListener.onResponse(imageContainer, true);    // 根据可以去检查该请求是否已经发起过    BatchedImageRequest request = mInFlightRequests.get(cacheKey);    if (request != null) {        request.addContainer(imageContainer);        return imageContainer;    }    Request<?> newRequest =        new ImageRequest(requestUrl, new Listener<Bitmap>() {            @Override            public void onResponse(Bitmap response) {            //如果请求成功                onGetImageSuccess(cacheKey, response);            }        }, maxWidth, maxHeight,        Config.RGB_565, new ErrorListener() {            @Override            public void onErrorResponse(VolleyError error) {                onGetImageError(cacheKey, error);            }        });    //添加至请求队列中    mRequestQueue.add(newRequest);    //同一添加进map集合,以方便检查该request是否正在请求网络,可以节约资源    mInFlightRequests.put(cacheKey, new BatchedImageRequest(newRequest, imageContainer));    return imageContainer;}
private void onGetImageSuccess(String cacheKey, Bitmap response) {//缓存对象    mCache.putBitmap(cacheKey, response);    // 请求完成,不需要检测    BatchedImageRequest request = mInFlightRequests.remove(cacheKey);    if (request != null) {        request.mResponseBitmap = response;        //处理结果        batchResponse(cacheKey, request);    }}
private void batchResponse(String cacheKey, BatchedImageRequest request) {    mBatchedResponses.put(cacheKey, request);    //通过handler,发送一个操作    if (mRunnable == null) {        mRunnable = new Runnable() {            @Override            public void run() {                for (BatchedImageRequest bir : mBatchedResponses.values()) {                    for (ImageContainer container : bir.mContainers) {                        if (container.mListener == null) {                            continue;                        }                        if (bir.getError() == null) {                            container.mBitmap = bir.mResponseBitmap;                            //更新结果                            container.mListener.onResponse(container, false);                        } else {                            container.mListener.onErrorResponse(bir.getError());                        }                    }                }                mBatchedResponses.clear();                mRunnable = null;            }        };        // mHandler对应的looper是MainLooper,因此被MainLooper.loop()得到该message,故该runnable操作在主线程中执行,        mHandler.postDelayed(mRunnable, mBatchResponseDelayMs);    }}

3.总结


RequestQueue类存在2个非常重要的PriorityBlockingQueue类型的成员字段mCacheQueue mNetworkQueue ,该PriorityBlockingQueue为java1.5并发库提供的!其中有几个重要的方法,比如take()为从队列中取得对象,如果队列不存在对象,将会被阻塞,直到队列中存在有对象,类似于Looper.loop()。实例化一个request对象,调用RequestQueue.add(request),该request如果不允许被缓存,将会被添加至mNetworkQueue队列中,待多个NetworkDispatcher线程从mNetworkQueue中take()取出对象。如果该request可以被缓存,该request将会被添加至mCacheQueue队列中,待mCacheDispatcher线程从mCacheQueue.take()取出对象,如果该request在mCache中不存在匹配的缓存时,该request将会被移交添加至mNetworkQueue队列中,待网络访问完成后,将关键头信息添加至mCache缓存中去,并通过ResponseDelivery主线程调用request的相关方法!

Volley实例,>>Android_开源框架_Volley实例

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 备孕子宫内膜厚怎么办 有成熟卵泡不破怎么办 卵泡不排萎缩了怎么办 卵泡8mm一直不长怎么办 卵泡已经长到28x19mm怎么办 多囊卵巢卵泡长不大怎么办 优势卵泡19不排怎么办 多囊卵泡不排卵怎么办 卵泡两天长2mm怎么办 子宫小43*38*26怎么办 优势卵泡打破卵针后并不破怎么办 ktv禁止自带酒水怎么办 记名西瓜卡丢了怎么办 日本电车卡丢了怎么办 网贷暂时没钱还怎么办 华泰倒闭了汽车怎么办 猫躲起来找不到了怎么办 狗生病了不吃饭怎么办 猫猫托运后害怕怎么办 新来的猫害怕怎么办 升工资老板不公平对待怎么办 自酿啤酒苦味重怎么办 自酿啤酒酸味重怎么办 微信电话费充错了怎么办 支付宝电话费充错了怎么办 在淘宝上充错电话费了怎么办 话费1000充错了怎么办 东西掉在地铁上怎么办 高铁安检丢东西怎么办 东西掉成都地铁上怎么办 东西掉在成都地铁上怎么办 成都地铁上掉东西了怎么办 地铁站丢了东西怎么办 在地铁站丢了东西怎么办 没有签劳动合同不发工资怎么办 没有劳动合同辞职不给工资怎么办 地铁安检要交押金怎么办 在广州地铁上人走丢了怎么办 海尔全自动洗衣机程系乱了怎么办 河南危险化学品经营许可证怎么办 甲方不给付监理费怎么办