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);
}
});
}
点击下载源码
想起刚开始写代码的时候,领导叫我写一个头像下载的方法,当时屁颠屁颠就写了一个图片下载的,每次都要去网络上请求,最后直接被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);
}
});
}
点击下载源码
相关文章推荐
- 自定义Android Studio方法注释模板
- RxAndroid与RxJava 变换的原理值lift()
- TabHost的两种用法-Android学习笔记
- TabIndicator+ViewPager实现左右滑动菜单效果
- 2015年十大热门Android开源新项目
- Android开发之内容提供者——创建自己的ContentProvider(详解)
- Android编程开发之TextView文字显示和修改方法(附TextView属性介绍)
- android Graphics( 五):drawText()详解
- 浅谈android线程池
- Android 快速开发系列 打造万能的ListView GridView 适配器
- Android surfaceview详解(一)
- Android 自动建表
- Android的内存优化
- Android CTS測试Fail项改动总结(四)
- MAC中设置android adb环境变量
- Android ActionBarDrawerToggle、DrawerLayout、ActionBar 结合
- android 自定义动画(一)
- AndroidManifest.xml file missing!
- Android 图片选择和裁剪 之 PictureTool
- Android访问服务器出现W/System.err(9302): java.io.FileNotFoundException:怎么办