从上一篇文章LruCache的源码简介中,我想我们可以知道LruCache的基本实现原理了!如果没有了解的可以先看看LruCache的基本介绍。
首先,我们要覆写sizeof这个方法。如下:
int maxCache = (int) (Runtime.getRuntime().maxMemory() / 1024);//得到应用的最大可用内存
int cacheSize = maxCache / 8; //一般情况下最多为可用内存的1/8
mLruCache = new LruCache(cacheSize){
@Override
protected int sizeOf(String key, Bitmap value) {
if(value != null)
return value.getByteCount() / 1024;
return 0;
}
};
然后,检查LruCache的缓存中是否有对应的key值,如果有就返回对应的Bitmap,如果没有则开异步线程去下载图片后再存入LruCache。其中核心代码如下:
/**
* 通过key值从LruCache中获取缓存对象
*
* @param key
* @return 如果LruCache存在该key则返回缓存的bitmap,否则返回null
*/
private Bitmap getBitmapFromCache(String key){
return mLruCache.get(key);
}
/**
* 通过key将Bitmap缓存到LruCache中
*
* @param key
* @param bitmap
*/
private void putBitmapToCache(String key, Bitmap bitmap){
if(getBitmapFromCache(key) == null && bitmap != null)
mLruCache.put(key, bitmap);
}
MainActivity:
package com.richardli.lrucachedemo_1;
import android.app.Activity;
import android.os.Bundle;
import android.widget.GridView;
public class MainActivity extends Activity {
private GridView mGridView;
private LruCacheImgAdapter mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
}
private void init(){
mGridView = (GridView) findViewById(R.id.imgsGridView);
mAdapter = new LruCacheImgAdapter(this, imageThumbUrls ,mGridView);
mGridView.setAdapter(mAdapter);
}
@Override
protected void onDestroy() {
super.onDestroy();
mAdapter.cancelAllDowanTask();
mAdapter.clearAllCache();
mAdapter = null;
System.gc();
}
/**
* 图片资源从郭神博客中抠出来的,呵呵...
*/
public final static String[] imageThumbUrls = new String[] {
"https://img-my.csdn.net/uploads/201407/26/1406383299_1976.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406383291_6518.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406383291_8239.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406383290_9329.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406383290_1042.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406383275_3977.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406383265_8550.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406383264_3954.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406383264_4787.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406383264_8243.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406383248_3693.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406383243_5120.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406383242_3127.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406383242_9576.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406383242_1721.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406383219_5806.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406383214_7794.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406383213_4418.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406383213_3557.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406383210_8779.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406383172_4577.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406383166_3407.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406383166_2224.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406383166_7301.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406383165_7197.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406383150_8410.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406383131_3736.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406383130_5094.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406383130_7393.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406383129_8813.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406383100_3554.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406383093_7894.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406383092_2432.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406383092_3071.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406383091_3119.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406383059_6589.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406383059_8814.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406383059_2237.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406383058_4330.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406383038_3602.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406382942_3079.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406382942_8125.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406382942_4881.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406382941_4559.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406382941_3845.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406382924_8955.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406382923_2141.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406382923_8437.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406382922_6166.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406382922_4843.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406382905_5804.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406382904_3362.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406382904_2312.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406382904_4960.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406382900_2418.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406382881_4490.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406382881_5935.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406382880_3865.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406382880_4662.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406382879_2553.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406382862_5375.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406382862_1748.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406382861_7618.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406382861_8606.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406382861_8949.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406382841_9821.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406382840_6603.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406382840_2405.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406382840_6354.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406382839_5779.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406382810_7578.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406382810_2436.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406382809_3883.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406382809_6269.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406382808_4179.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406382790_8326.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406382789_7174.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406382789_5170.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406382789_4118.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406382788_9532.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406382767_3184.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406382767_4772.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406382766_4924.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406382766_5762.jpg",
"https://img-my.csdn.net/uploads/201407/26/1406382765_7341.jpg"
};
}
LruCacheImgAdapter适配器:
package com.richardli.lrucachedemo_1;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import javax.net.ssl.HttpsURLConnection;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.support.v4.util.LruCache;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.ImageView;
public class LruCacheImgAdapter extends BaseAdapter implements OnScrollListener{
private Context mContext;
private LayoutInflater mInflater;
private String[] mImgsList;
private GridView mGridView;
private LruCache mLruCache;//所有图片缓存
private List mDownloadTastAllList; //所有异步下载集合
private int mFirstVisibleItem;//当前可见列表的第一项
private int mVisibleItemCount;//当前可见表项个数
private boolean isFirstCome = true;// 是否是第一次进入加载
public LruCacheImgAdapter(Context ctx , String[] imgs , GridView mGridView){
this.mContext = ctx;
this.mImgsList = imgs;
this.mGridView = mGridView;
this.mGridView.setOnScrollListener(this);
mInflater = LayoutInflater.from(mContext);
mDownloadTastAllList = new ArrayList();
initLruCache();
}
private void initLruCache(){
int maxCache = (int) (Runtime.getRuntime().maxMemory() / 1024);//得到应用的最大可用内存
int cacheSize = maxCache / 8; //一般情况下最多为可用内存的1/8
mLruCache = new LruCache(cacheSize){
@Override
protected int sizeOf(String key, Bitmap value) {
if(value != null)
return value.getByteCount() / 1024;
return 0;
}
};
}
@Override
public int getCount() {
return mImgsList.length;
}
@Override
public Object getItem(int position) {
return mImgsList[position];
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder mViewHolder = null;
if(convertView == null){
convertView = mInflater.inflate(R.layout.img_grid_item_layout, parent , false);
mViewHolder = new ViewHolder();
mViewHolder.mImagsView = (ImageView) convertView.findViewById(R.id.img_show_iv);
convertView.setTag(mViewHolder);
}else{
mViewHolder = (ViewHolder) convertView.getTag();
}
String url = mImgsList[position];
mViewHolder.mImagsView.setTag(url);
displayImage(url , mViewHolder.mImagsView);
return convertView;
}
private static class ViewHolder{
ImageView mImagsView;
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if(scrollState == SCROLL_STATE_IDLE)
loadBitmap(mFirstVisibleItem, mVisibleItemCount);
else
cancelAllDowanTask();
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
mFirstVisibleItem = firstVisibleItem;
mVisibleItemCount = visibleItemCount;
if(isFirstCome && visibleItemCount > 0){
isFirstCome = false;
loadBitmap(mFirstVisibleItem, mVisibleItemCount);
}
}
private void displayImage(String url, ImageView imgView){
Bitmap mCacheBtimap = getBitmapFromCache(url);
if(mCacheBtimap != null)
imgView.setImageBitmap(mCacheBtimap);
else
imgView.setBackgroundResource(android.R.color.holo_orange_dark);
}
private void loadBitmap(int mFirstVisibleItem, int mVisibleItemCount){
for(int i = mFirstVisibleItem ; i < mFirstVisibleItem + mVisibleItemCount ; i++){
String url = mImgsList[i];
// 判断图片是否存在缓存中,如果存在则不下载。
Bitmap bitmap = getBitmapFromCache(url);
if(bitmap != null){
ImageView imgView = (ImageView) mGridView.findViewWithTag(url);
if(imgView != null)
imgView.setImageBitmap(bitmap);
}else{
//开启异步任务下载图片
DownloadAsyncTask downTask = new DownloadAsyncTask();
mDownloadTastAllList.add(downTask);
downTask.execute(url);
}
}
}
/**
* 通过key值从LruCache中获取缓存对象
*
* @param key
* @return 如果LruCache存在该key则返回缓存的bitmap,否则返回null
*/
private Bitmap getBitmapFromCache(String key){
return mLruCache.get(key);
}
/**
* 通过key将Bitmap缓存到LruCache中
*
* @param key
* @param bitmap
*/
private void putBitmapToCache(String key, Bitmap bitmap){
if(getBitmapFromCache(key) == null && bitmap != null)
mLruCache.put(key, bitmap);
}
/**
* 清除所有缓存
*/
public void clearAllCache(){
if(mLruCache != null){
if(mLruCache.size() > 0)
mLruCache.evictAll();
mLruCache = null;
}
}
/**
* 通过url异步下载图片,下载成功后保存至缓存中,并显示
* @author Rrichard
*
*/
class DownloadAsyncTask extends AsyncTask{
private String imgUrl ;
@Override
protected Bitmap doInBackground(String... params) {
imgUrl = params[0];
Bitmap bitmap = getBitmapForUrl(imgUrl);
if(bitmap != null)
putBitmapToCache(imgUrl , bitmap);
return bitmap;
}
@Override
protected void onPostExecute(Bitmap result) {
super.onPostExecute(result);
ImageView mImageView = (ImageView) mGridView.findViewWithTag(imgUrl);
if(mImageView != null && result != null){
mImageView.setImageBitmap(result);
mDownloadTastAllList.remove(this);
}
}
}
/**
* 取消所有下载任务
*/
public void cancelAllDowanTask(){
if(mDownloadTastAllList != null && mDownloadTastAllList.size() != 0){
for(DownloadAsyncTask task : mDownloadTastAllList)
task.cancel(true);
}
}
/**
* 通过URL下载图片
*
* @param url
* @return
*/
private Bitmap getBitmapForUrl(String url){
Bitmap bitmap = null;
HttpURLConnection connection = null;
try {
URL mUrl = new URL(url);
connection = (HttpURLConnection) mUrl.openConnection();
connection.setConnectTimeout(10 * 1000);
connection.setReadTimeout(10 * 1000);
connection.setDoInput(true);
connection.setDoOutput(true);
connection.connect();
if(connection.getResponseCode() == HttpsURLConnection.HTTP_OK)
bitmap = BitmapFactory.decodeStream(connection.getInputStream());
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
if(connection != null){
connection.disconnect();
connection = null;
}
}
return bitmap;
}
}
效果图用应用宝编辑的,搞得不是很好。不要介意,将就着看
到这里就是一个简单的LruCache图片缓存的使用,但是,在实际开发中我们肯定不能像上面这样使用。因为很明显嘛,上面的代码有很多问题。比如:下载图片时,一个个下载这效率特低了吧!而且很容易出现异常。图片下载下来,图片太大了会出现OOM,因为图片没有压缩采样处理。所以,我们先就图片的处理来进行一下简单的修改。
/**
* 通过URL下载图片
*
* @param url
* @return
*/
private Bitmap getBitmapForUrl(String url){
Bitmap bitmap = null;
HttpURLConnection connection = null;
try {
URL mUrl = new URL(url);
connection = (HttpURLConnection) mUrl.openConnection();
connection.setConnectTimeout(10 * 1000);
connection.setReadTimeout(10 * 1000);
connection.setDoInput(true);
connection.setDoOutput(true);
connection.connect();
if(connection.getResponseCode() == HttpsURLConnection.HTTP_OK){
InputStream inputStream = connection.getInputStream();
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while( (len=inputStream.read(buffer)) != -1){
outStream.write(buffer, 0, len);
}
outStream.close();
inputStream.close();
byte[] data = outStream.toByteArray();
if(data != null){
// 进行采样压缩图片
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(data, 0, data.length , options);
int height = options.outHeight;
int width = options.outWidth;
int inSampleSize = 1;
if(height > 150 || width > 150){
int heightSize = Math.round(height / 80);
int widthSize = Math.round(width / 80);
inSampleSize = heightSize >= widthSize ? widthSize : heightSize;
}
options.inSampleSize = inSampleSize;
options.inJustDecodeBounds = false;
bitmap = BitmapFactory.decodeByteArray(data, 0, data.length , options);;
}
}
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
if(connection != null){
connection.disconnect();
connection = null;
}
}
return bitmap;
}
当然这代码也不是写得很好,只是举个简单的例子。实际开发中肯定不能这样做,得剥离出来,进行优化。所以后面的就留到下一篇博客在写吧!
Demo下载地址:http://download.csdn.net/detail/richardli1228/9296797