当前位置: 代码迷 >> Android >> Android Volley分析(2)——实现
  详细解决方案

Android Volley分析(2)——实现

热度:82   发布时间:2016-04-28 03:08:09.0
Android Volley分析(二)——实现

在Android Volley分析(一)——结构中主要分析了Volley的基本组件和框架结构,组件主要是定义的接口,也就是说我们可以实现这些接口来定制自己的Volley版本,比如NetWork、Cache、Request等等。Android Volley在com.android.volley.toolbox下已经做了这些工作,下面就看看这些具体的实现内容


先看一个Volley使用的例子

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教程的一个例子,使用Volley的步骤

1、Volley.newRequestQueue();

2、new Request();

3、queue.add(request);

在newRequestQueue的时候会初始化基本的组件

    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 {                // Prior to Gingerbread, HttpUrlConnection was unreliable.                // See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html                stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));            }        }        Network network = new BasicNetwork(stack);        RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);        queue.start();        return queue;    }

1、BasicNetwork

BasicNetwork是对Network接口的实现,同时还将联网操作部分提取出来形成HttpStack,原因是Android 2.3之前网络操作推荐使用HttpClient,2.3之后Android做了优化推荐使用HttpUrlConnection。

2、DiskBasedCache

DiskBasedCache是对Cache对实现,用于硬盘缓存,也就是将数据保存为特定的文件。

结合LruCache试着总结一下缓存的一般方法:

映射结构——LinkedHashMap,内部实现了Lru的算法排序,可以直接使用

put——存储,容量计数增加,判断是否超出最大容量,超出则删除最少使用的

get——key到entry的映射

remove——删除,容量计数减小

3、ImageLoader

ImageLoader是一个图片加载类,封装了请求,提供了内存缓存机制,批处理等,让图片加载更容易使用,下面看一下它的用法:

        mImageLoader = new ImageLoader(mRequestQueue,                new ImageLoader.ImageCache() {            private final LruCache<String, Bitmap>                    cache = new LruCache<String, Bitmap>(20);            @Override            public Bitmap getBitmap(String url) {                return cache.get(url);            }            @Override            public void putBitmap(String url, Bitmap bitmap) {                cache.put(url, bitmap);            }
mImageLoader.get(IMAGE_URL, ImageLoader.getImageListener(mImageView,         R.drawable.def_image, R.drawable.err_image));

(示例来源 Making a Standard Request )

内存缓存推荐使用LruCache,需要实现ImageLoader.ImageCache接口。图片的加载通过imageLoader.get()方法实现,

    public ImageContainer get(String requestUrl, ImageListener imageListener,            int maxWidth, int maxHeight) {        // only fulfill requests that were initiated from the main thread.        throwIfNotOnMainThread();        final String cacheKey = getCacheKey(requestUrl, maxWidth, maxHeight);        // Try to look up the request in the cache of remote images.        Bitmap cachedBitmap = mCache.getBitmap(cacheKey);        if (cachedBitmap != null) {            // Return the cached bitmap.            ImageContainer container = new ImageContainer(cachedBitmap, requestUrl, null, null);            imageListener.onResponse(container, true);            return container;        }        // The bitmap did not exist in the cache, fetch it!        ImageContainer imageContainer =                new ImageContainer(null, requestUrl, cacheKey, imageListener);        // Update the caller to let them know that they should use the default bitmap.        imageListener.onResponse(imageContainer, true);        // Check to see if a request is already in-flight.        BatchedImageRequest request = mInFlightRequests.get(cacheKey);        if (request != null) {            // If it is, add this request to the list of listeners.            request.addContainer(imageContainer);            return imageContainer;        }        // The request is not already in flight. Send the new request to the network and        // track it.        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);        mInFlightRequests.put(cacheKey,                new BatchedImageRequest(newRequest, imageContainer));        return imageContainer;    }

首先得到一个cacheKey,这个是统一的规则

    private static String getCacheKey(String url, int maxWidth, int maxHeight) {        return new StringBuilder(url.length() + 12).append("#W").append(maxWidth)                .append("#H").append(maxHeight).append(url).toString();    }

然后在缓存cache中查找,没找到就讲请求添加到批处理任务BitmapImageRequest中,这里有两个类,ImageContainer和BitmapImageRequest:

ImageContainer是一个包装类,里面包含了bitmap、url、cacheKey和listener,当得到bitmap后会通过listener将bitmap返回;

BitmapImageRequest是将相同url请求放在一起,这样就可以只向网络请求一次,返回结果后再分别设置到目标上,从而达到减少网络请求对目的。


  相关解决方案