码迷,mamicode.com
首页 > 移动开发 > 详细

安卓网络请求图片到图片的三级缓存技术(内存缓存,本地缓存,网络缓存)

时间:2016-08-12 23:24:15      阅读:252      评论:0      收藏:0      [点我收藏+]

标签:

安卓网络请求图片,对于我们来说并不陌生,因为每个应用都有可能会用到这一技术。通常情况下,我们第一次都是从网络上请求图片资源,然后将

图片资源保存到内存和本地,下一次动态显示图片的时候就不需要再从网络上请求图片资源了,直接从本地或者内存中获取就可以了。这就涉及到图片

的三级缓存技术,分别是内存缓存,本地缓存,网络缓存。

 

缓存的流程图:

技术分享

首先我们定义一个类叫ClassLoader:

package com.jsako.showprodinfodemo;

import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.support.v4.util.LruCache;
import android.widget.ImageView;

/**
 * 图片加载类
 * 
 * @author Administrator
 * 
 */
public class ImageLoader {
    private Context context;
    private int loadingImage;
    private int errorImage;
    private LruCache<String, Bitmap> mapCache;
    public ImageLoader(Context context, int loadingImage, int errorImage) {
        this.context = context;
        this.loadingImage = loadingImage;
        this.errorImage = errorImage;
        int maxMemory = (int) Runtime.getRuntime().maxMemory();
        int mCacheSize = maxMemory / 8;
        mapCache = new LruCache<String, Bitmap>(mCacheSize) {
            @Override
            protected int sizeOf(String key, Bitmap value) {
                return value.getRowBytes() * value.getHeight();
            }
        };
    }

    public void getAndSetImage(String imagePath, ImageView iv_image) {
        //保存当前的ImageView对应的imagepath
        iv_image.setTag(imagePath);
        iv_image.setImageResource(loadingImage);
        /*
         * 从第一级缓存中找对应imagePath的图片 如果第一级缓存有对应图片,显示! 如果第一级缓存没有图片,从第二级缓存中找
         */
        Bitmap bitmap = getImageByFirstCache(imagePath);
        if (bitmap != null) {
            iv_image.setImageBitmap(bitmap);
            System.out.println("从一级缓存中找到");
            return;
        }
        /*
         * 从第二级缓存中找对应的图片 如果有,则缓存到第一缓存中 如果没有,则从第三集缓存中找
         */
        bitmap = getImageBySecondCache(imagePath);
        if (bitmap != null) {
            iv_image.setImageBitmap(bitmap);
            cacheInFirst(imagePath, bitmap);
            System.out.println("从二级缓存中找到");
            return;
        }

        /*
         * 从第三级缓存中找对应的图片 如果有,则缓存到第一、二缓存中 如果没有,则显示错误的图片
         */
        loadImageByThridCache(imagePath, iv_image);
    }

    /**
     * 将图片缓存到一级缓存
     * 
     * @param imagePath
     *            图片的url
     * @param bitmap
     */
    private void cacheInFirst(String imagePath, Bitmap bitmap) {

        mapCache.put(imagePath, bitmap);
    }

    /**
     * 从三级缓存中寻找图片
     * 
     * @param imagePath
     *            图片的url
     * @param
     * @return
     */
    private void loadImageByThridCache(final String imagePath,
            final ImageView iv_image) {
        new AsyncTask<String, Void, Bitmap>() {
            /**
             * 开启异步任务前调用
             */
            @Override
            protected void onPreExecute() {

            }

            /**
             * 异步任务完成后调用
             */
            @Override
            protected void onPostExecute(Bitmap result) {
                String nowImagePath=(String) iv_image.getTag();
                if(!nowImagePath.equals(imagePath)){
                    //如果当前请求的图片路径和需要显示的图片路径不一致的话,就不显示图片
                    System.out.println("不显示图片了");
                    return;
                }
                
                if (result != null) {
                    iv_image.setImageBitmap(result);
                } else {
                    iv_image.setImageResource(errorImage);
                }
            }

            /**
             * 后台进行异步任务
             */
            @Override
            protected Bitmap doInBackground(String... params) {
                String nowImagePath=(String) iv_image.getTag();
                if(!nowImagePath.equals(params[0])){
                    //如果当前请求的图片路径和需要显示的图片路径不一致的话,就不进行网络请求了
                    System.out.println("不进行网络请求了");
                    return null;
                }
                String url = params[0];
                HttpURLConnection conn = null;
                try {
                    URL mUrl = new URL(url);
                    conn = (HttpURLConnection) mUrl.openConnection();
                    conn.setRequestMethod("GET");
                    conn.setReadTimeout(6000);
                    conn.setConnectTimeout(6000);
                    conn.setDoInput(true);
                    conn.connect();

                    int code = conn.getResponseCode();
                    if (code == 200) {
                        InputStream in = conn.getInputStream();
                        Bitmap bitmap = BitmapFactory.decodeStream(in);
                        // 在分线程中缓存图片到一级和二级缓存
                        cacheInFirst(url, bitmap);
                        String imageName = url
                                .substring(url.lastIndexOf("/") + 1);
                        String fileName = context.getExternalFilesDir(null)
                                .getAbsolutePath() + "/" + imageName;
                        bitmap.compress(CompressFormat.JPEG, 50,
                                new FileOutputStream(fileName));
                        return bitmap;
                    } else {
                        return null;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    return null;
                } finally {
                    if (conn != null) {
                        conn.disconnect();
                    }
                }
            }
        }.execute(imagePath);
    }

    /**
     * 从二级缓存中寻找图片
     * 
     * @param imagePath
     *            图片的url
     * @return
     */
    private Bitmap getImageBySecondCache(String imagePath) {
        String imageName = imagePath.substring(imagePath.lastIndexOf("/") + 1);
        String fileName = context.getExternalFilesDir(null).getAbsolutePath()
                + "/" + imageName;
        return BitmapFactory.decodeFile(fileName);
    }

    /**
     * 从一级缓存中寻找图片
     * 
     * @param imagePath
     *            图片的url
     * @return
     */
    private Bitmap getImageByFirstCache(String imagePath) {
        return mapCache.get(imagePath);
    }

}

可以看到这个类的构造方法有三个,第一个是上下文,第二个是加载的图片的时候所显示的图片对应的资源id,第三个是图片加载失败后所显示的图片对应的资源id。

这里有几个关键点:

第一个是在内存缓存中,我们应该使用LruCache来缓存图片,这个类会根据当前所存储的图片空间是否大过设定值,如果比设定值大就会自动释放内存,

这样就能防止内存溢出的问题。

 

第二个是在使用ListView异步加载图片的时候,并且重用了convertView的时候会导致图片错位的现象。

导致图片错位的根本原因就是重用了convertView。

解决方案如下:

a. 每次getView()都将图片的url保存到ImageView上: imageView.setTag(imagePath)
b. 在分线程准备请求服务器加载图片之前, 比较准备加载图片的url与ImageView中保存的最新图片的url是同一个,
如果不是同一个, 当前加载图片的任务不应该再执行
如果相同, 继续执行加载远程图片
c. 在主线程准备显示图片之前, 比较加载到图片的url与ImageView中保存的最新图片的url是同一个
如果不是同一个, 不需要显示此图片
如果相同, 显示图片

安卓网络请求图片到图片的三级缓存技术(内存缓存,本地缓存,网络缓存)

标签:

原文地址:http://www.cnblogs.com/Jsako/p/5766642.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!