您的位置:首页 > 移动开发 > Android开发

Android图片二级缓存

2015-12-29 09:46 483 查看
点击下载源码

想起刚开始写代码的时候,领导叫我写一个头像下载的方法,当时屁颠屁颠就写了一个图片下载的,每次都要去网络上请求,最后直接被pass掉了

当时的思路是这样的



后来渐渐地就知道了有二级缓存这东西。自己也阅读过很多关于双缓存的文章。

APP开发到越后面,对性能的要求越高,那么双缓存的优势就逐渐体现出来了。

所谓图片双缓存,首先到运行内存中请求,再到sd卡请求,最后到网络请求,流程图如下



那我们从第一部开始解析

1.先看 内存缓存的代码

[java] view
plaincopy

public class MemoryCache implements ImageCache {

private static final String TAG = MemoryCache.class.getSimpleName();

private LruCache<String,Bitmap> mMemoryCache;

public MemoryCache(){

init();

}

private void init(){

final int maxMemory = (int) (Runtime.getRuntime().maxMemory()/1024);

final int cacheSize = maxMemory/4;

mMemoryCache = new LruCache<String,Bitmap>(cacheSize){

@Override

protected int sizeOf(String key, Bitmap value) {

return value.getRowBytes()*value.getHeight()/1024;

}

};

}

@Override

public Bitmap get(String key) {

Bitmap bitmap = mMemoryCache.get(key);

if (bitmap!=null){

Log.i(TAG,"File is exist in memory");

}

return mMemoryCache.get(key);

}

@Override

public void put(String key, Bitmap bitmap) {

if (get(key)==null) {

mMemoryCache.put(key, bitmap);

}

}

}

[java] view
plaincopy

private void init()

init()方法中对一些变量进行初始化,mMemoryCache用于在内存中缓存图片

[java] view
plaincopy

public Bitmap get(String key) {}

get()方法用于从内存中获得缓存

[java] view
plaincopy

public void put(String key, Bitmap bitmap) {}

put()方法将下载好的图片缓存到内存中,方便下次使用

2.再看sd卡缓存

[java] view
plaincopy

public class DiskCache implements ImageCache {

private static final String TAG = DiskCache.class.getSimpleName();

static String mPath ;

public DiskCache(Context context){

init(context);

}

private void init(Context context){

// 获取图片缓存路径

mPath = getDiskCachePath(context,"bitmap");

File cacheDir = new File(mPath);

if (!cacheDir.exists()) {

cacheDir.mkdirs();

}

}

@Override

public Bitmap get(String key) {

File file = new File(mPath+key);

if (file.exists()){

return BitmapFactory.decodeFile(mPath+key);

}

return null;

}

@Override

public void put(String key, Bitmap bitmap) {

FileOutputStream fileOutputStream = null;

try {

File file = new File(mPath+key);

if (file.exists()){

Log.i(TAG,"File is exist on disk");

}

fileOutputStream = new FileOutputStream(mPath+key);

bitmap.compress(Bitmap.CompressFormat.PNG,100,fileOutputStream);

} catch (FileNotFoundException e) {

e.printStackTrace();

}finally {

CloseUtils.closeQuietly(fileOutputStream);

}

}

/**

* 根据传入的dir获得路径

* @param context

* @param dir

* @return

*/

public String getDiskCachePath(Context context, String dir) {

String cachePath;

if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())

|| !Environment.isExternalStorageRemovable()) {

cachePath = context.getExternalCacheDir().getPath();

} else {

cachePath = context.getCacheDir().getPath();

}

return cachePath + File.separator + dir;

}

}

同样

[java] view
plaincopy

private void init()

init()方法中对一些变量进行初始化,mMemoryCache用于在内存中缓存图片

[java] view
plaincopy

public Bitmap get(String key) {}

get()方法用于从内存中获得缓存

[java] view
plaincopy

public void put(String key, Bitmap bitmap) {}

put()方法将下载好的图片缓存到内存中,方便下次使用

接下来我们会在一个叫DoubleCache的类中对以上两种缓存方式进行管理

[java] view
plaincopy

public class DoubleCache implements ImageCache {

private static final String TAG = DoubleCache.class.getSimpleName();

private MemoryCache mMemoryCache = null;

private DiskCache mDiskCache = null;

public DoubleCache(Context context){

mMemoryCache = new MemoryCache();

mDiskCache = new DiskCache(context);

}

@Override

public Bitmap get(String url) {

String key = url2Key(url);

Bitmap bitmap = mMemoryCache.get(key);

if(bitmap==null){

bitmap = mDiskCache.get(key);

}else {

}

return bitmap;

}

@Override

public void put(String url, Bitmap bitmap) {

String key = url2Key(url);

mMemoryCache.put(key,bitmap);

mDiskCache.put(key,bitmap);

}

//url转key

private String url2Key(String url){

String key = MD5.hashKeyForDisk(url)+".jpg";

return key;

}

}

我们在获取缓存的时候先从内存中获取,当内存中击中直接返回,当内存中没有击中,则访问sd卡。

3.看到这里,小伙伴们一定急了,这只有从缓存中和sd卡中取图片,并没有从网络获取,别急,马上就来

[java] view
plaincopy

public class ImageLoader {

private static final String TAG = ImageLoader.class.getSimpleName();

private static ImageLoader sInstance;

private DoubleCache mDoubleCache = null;

private ExecutorService mExecutorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

private ImageLoader(Context context) {

mDoubleCache = new DoubleCache(context);

}

public static ImageLoader getInstance(Context context) {

if (sInstance == null) {

synchronized (ImageLoader.class) {

sInstance = new ImageLoader(context);

}

}

return sInstance;

}

public void displayImage(String url, ImageView imageView) {

Bitmap bitmap = mDoubleCache.get(url);

if (bitmap != null) {

imageView.setImageBitmap(bitmap);

mDoubleCache.put(url,bitmap);

return;

}

submitLoadRequest(url, imageView);

}

private void submitLoadRequest(final String url, final ImageView imageView) {

Log.i(TAG,"Download,url:"+url);

imageView.setTag(url);

mExecutorService.submit(new Runnable() {

@Override

public void run() {

final Bitmap bitmap = downloadImage(url);

if (imageView.getTag().equals(url)) {

imageView.post(new Runnable() {

@Override

public void run() {

imageView.setImageBitmap(bitmap);

}

});

}

mDoubleCache.put(url, bitmap);

}

});

}

Handler handler = new Handler(){

@Override

public void handleMessage(Message msg) {

}

};

public Bitmap downloadImage(String url) {

Bitmap bitmap = null;

HttpURLConnection conn = null;

try {

URL url1 = new URL(url);

conn = (HttpURLConnection) url1.openConnection();

bitmap = BitmapFactory.decodeStream(conn.getInputStream());

if (bitmap!=null){

mDoubleCache.put(url,bitmap);

}

} catch (MalformedURLException e) {

e.printStackTrace();

} catch (Exception e) {

e.printStackTrace();

} finally {

if (conn != null) {

conn.disconnect();

}

}

return bitmap;

}



[java] view
plaincopy

displayImage()

方法中可以看到,如果缓存中都没有才从网络中获取

[java] view
plaincopy

public Bitmap downloadImage(String url) {}

下载完成之后,把图片放到缓存中。

到这里,我们的第二张流程图就走完了。是不是很简单。

我们在看一下是如何使用的

[java] view
plaincopy

private ImageView imageView;

private ImageView imageView2;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

imageView = (ImageView) findViewById(R.id.image);

imageView2 = (ImageView) findViewById(R.id.image2);

imageView.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

ImageLoader.getInstance(MainActivity.this).displayImage("http://img.my.csdn.net/uploads/201407/26/1406383299_1976.jpg", imageView);

}

});

imageView2.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

ImageLoader.getInstance(MainActivity.this).displayImage("http://img.my.csdn.net/uploads/201407/26/1406383299_1976.jpg", imageView2);

}

});

}

点击下载源码
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: