在第二阶段中用LruCache实现了网络下载的图片的缓存,避免了重复下载图片,耗费流量。
首先要修改ImageLoader,其中被注释掉的代码就是一阶段中的代码:
public class ImageLoader {
// private ImageView mImageView;
// private String mUrl;
//在定义了一个成员变量mLruCache后,就不能每次在适配器的getView方法中去new一个ImageLoader了,因为下载的图片要缓存到同一LruCache中,不然就没用作用
//因此只是用简单的多线程去实现异步加载是不行的了,因为适配器中只有一个ImageLoader的实例,
//每次传入新的mImageView和mUrl的引用有可能会覆盖掉原来的引用,就会使得handleMessage
//在调用ImageLoader唯一实例的mImageView和mUrl这两个成员变量时也许会与msg.obj中的bitmap不对应
//所以sendMessage的时候,需要将showImageByThread方法的参数直接和bitmap绑定在一起传入message中
//因此mImageView和mUrl也没有作用了
private LruCache<String, Bitmap> mLruCache;
public ImageLoader() {
int maxMemory=(int) Runtime.getRuntime().maxMemory();
int cacheSize=maxMemory/5;
mLruCache=new LruCache<String, Bitmap>(cacheSize) {
@Override
protected int sizeOf(String key, Bitmap value) {
//在每次存入缓存的时候调用
return value.getByteCount();
};
};
}
public void addBitmapToCache(String url,Bitmap bitmap) {
if(mLruCache.get(url)==null) {
mLruCache.put(url, bitmap);
}
}
public Bitmap getBitmapFromCache(String url) {
return mLruCache.get(url);
}
//因为在getView中每次都new一个ImageLoader实例,因此都有一个新的 handler成员变量,
//所以尽管handleMessage是在主线程中进行,且handleMessage中用了ImageLoader实例mImageView和mUrl
//但是bitmap中的bitmap会与正确的mImageView和mUrl对应,不会因为多线程而发生错乱
private Handler handler=new Handler() {
@Override
public void handleMessage(android.os.Message msg) {
// if (mImageView.getTag().equals(mUrl)) {
// mImageView.setImageBitmap((Bitmap) msg.obj);
// }
ViewHolder vh=(ViewHolder)msg.obj;
Bitmap bm=vh.bm;
ImageView iv=vh.iv;
String url=vh.url;
if(iv.getTag().equals(url)) {
iv.setImageBitmap(bm);
}
}
};
/**
* 使用多线程实现异步加载
* @param iv
* @param url
*/
public void showImageByThread(final ImageView iv, final String url) {
// mImageView = iv;
// mUrl = url;
//
// new Thread() {
//
// @Override
// public void run() {
// Bitmap bitmap = getBitmapFromURL(url);
// Message message = Message.obtain();
// message.obj = bitmap;
// handler.sendMessage(message);
// }
// }.start();
Bitmap bitmap=getBitmapFromCache(url);
if (bitmap == null) {
new Thread() {
@Override
public void run() {
Bitmap bm = getBitmapFromURL(url);
Message message = Message.obtain();
ViewHolder vh=new ViewHolder();
vh.iv=iv;
vh.url=url;
vh.bm=bm;
message.obj = vh;
handler.sendMessage(message);
}
}.start();
}
else {
iv.setImageBitmap(bitmap);
}
}
private class ViewHolder {
public ImageView iv;
public String url;
public Bitmap bm;
}
/**
* 使用AsyncTask实现异步加载,showImageByAsyncTask自身是在主线程当中的
* @param iv
* @param url
*/
public void showImageByAsyncTask(final ImageView iv,final String url) {
Bitmap bitmap=getBitmapFromCache(url);
if (bitmap == null) {
new LoadingAsyncTask(iv, url).execute(url);
}
else {
iv.setImageBitmap(bitmap);
}
}
private class LoadingAsyncTask extends AsyncTask<String, Void, Bitmap> {
private ImageView imageView;
private String url;
public LoadingAsyncTask(ImageView iv,String url) {
imageView=iv;
this.url=url;
}
@Override
protected Bitmap doInBackground(String... params) {
Bitmap bm=getBitmapFromURL(params[0]);
if(bm!=null) {
addBitmapToCache(params[0], bm);
}
return bm;
}
@Override
protected void onPostExecute(Bitmap result) {
if (imageView.getTag().equals(url)) {
imageView.setImageBitmap(result);
}
}
}
public Bitmap getBitmapFromURL(String urlString) {
Bitmap bm=null;
InputStream is=null;
try {
URL url=new URL(urlString);
HttpURLConnection connection=(HttpURLConnection) url.openConnection();
is=new BufferedInputStream(connection.getInputStream());
bm=BitmapFactory.decodeStream(is);
connection.disconnect();//释放资源
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return bm;
}
}
然后是在NewsAdapter中添加成员变量mImageLoader并在构造方法中初始化mImageLoader=new ImageLoader();
再修改getView方法的部分代码
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder=null;
if(convertView==null) {
viewHolder=new ViewHolder();
convertView=mInflater.inflate(R.layout.item_layout, null);
viewHolder.icon=(ImageView) convertView.findViewById(R.id.id_icon);
viewHolder.title=(TextView) convertView.findViewById(R.id.id_tv_title);
viewHolder.content=(TextView) convertView.findViewById(R.id.id_tv_content);
convertView.setTag(viewHolder);
}
else {
viewHolder=(ViewHolder) convertView.getTag();
}
viewHolder.icon.setImageResource(R.drawable.ic_launcher);
String url=mList.get(position).newsIconUrl;
viewHolder.icon.setTag(url);
// new ImageLoader().showImageByAsyncTask(viewHolder.icon, url);
// new ImageLoader().showImageByThread(viewHolder.icon, url);
mImageLoader.showImageByAsyncTask(viewHolder.icon,url);
// mImageLoader.showImageByThread(viewHolder.icon, url);
viewHolder.title.setText(mList.get(position).newsTitle);
viewHolder.content.setText(mList.get(position).newsContent);
return convertView;
}