【Android】网络图片加载优化(一)利用弱引用缓存异步加载

应用背景

ListView 或GridView是一种可以显示一系列项目并能进行滚动显示的 View,每一行的Item可能包含复杂的结构。

其可能会从网络上获取一些图片信息,就现在的网络速度要想保持ListView运行的很好滚动流畅是做不到的。

所以这里就需要把这些信息利用多线程实现异步加载,同时,应用弱引用缓存技术方便再次加载时预览。

工作原理

使用了SoftReference来缓存图片,允许 GC在需要的时候可以对缓存中的图片进行清理。

它是这样工作:

(1) 调用 loadDrawable(ImageUrl, imageCallback),传入一个匿名实现的 ImageCallback接口;

(2)如果图片在缓存中不存在的话,图片将从单一的线程中下载并在下载结束时通过 ImageCallback回调;

(3)如果图片确实存在于缓存中,就会马上返回,不会回调 ImageCallback。

弱应用缓存类的封装

package com.wei.util;

import java.lang.ref.SoftReference;
import java.net.URL;
import java.util.HashMap;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Message;


public class AsyncImageLoader{
	Bitmap bitmap = null;
	HashMap<String, SoftReference<Bitmap>> imageCache;
	BitmapFactory.Options opts;
	// 1.根据URL返回Drawable的函数
	// 2.工具类的核心函数,包含handler+thread

	public AsyncImageLoader() {
		imageCache = new HashMap<String, SoftReference<Bitmap>>();
		opts = new BitmapFactory.Options();   
		opts.inSampleSize = 0;    //这个的值压缩的倍数(2的整数倍),数值越小,压缩率越小,图片越清晰    
	}

	public Bitmap asyncLoadImage(final String strUrl, final int i, final LoadFinishCallBack loadFinishCallBack) {
		Bitmap bitmap = null;
		//首先判断Map中是否有这种图片的缓存,若有,直接返回该图片的引用
		if(imageCache.containsKey(strUrl)) {
			SoftReference<Bitmap> softReference = imageCache.get(strUrl);
			bitmap = softReference.get();
			if(bitmap != null) {
				return bitmap;
			}
		}
		
		final Handler handler = new Handler() {
			@Override
			public void handleMessage(Message msg) {
				// 回调接口
				loadFinishCallBack.loadFinish(strUrl, i, (Bitmap) msg.obj);
			}
		};

		new Thread() {
			@Override
			public void run() {
				Bitmap bitmap = null;
				try {
					bitmap = BitmapFactory.decodeStream(new URL(strUrl).openConnection().getInputStream(), null, opts);	
				} catch (Exception e) {
					e.printStackTrace();
				}
				imageCache.put(strUrl, new SoftReference<Bitmap>(bitmap));//第一次拿某张图片,把该图片的引用放入缓存中
				Message msg = new Message();
				msg.obj = bitmap;
				//System.out.println("bitmap 宽高"+bitmap.getWidth()+"-"+bitmap.getHeight());
				handler.sendMessage(msg);
			}
		}.start();

		return bitmap;
	}

	public interface LoadFinishCallBack {
		public void loadFinish(String strUrl, int i, Bitmap bitmap);
	}
}

弱引用缓存类的应用

			Bitmap bm = asyncImageLoader.asyncLoadImage(strUrl, 0, callback);
			oneView.image.setImageBitmap(null);
			if(bm==null) {
				oneView.image.setBackgroundResource(R.drawable.slt);
			} else {
				oneView.image.setImageBitmap(bm);
			}
其中,asyncImageLoader是上述封装类的实例,R.drawable.slt是图片未加载出来时显示的图片资源。
callback是所调用的接口:
	//图片下载成功后执行的回调接口
	LoadFinishCallBack callback = new LoadFinishCallBack() {
		@Override
		public void loadFinish(String strUrl, int i, Bitmap bitmap) {
			if (bitmap != null) {
				ImageView imageView = (ImageView) gridView.findViewWithTag(strUrl);
				if(imageView != null) {
					imageView.setImageBitmap(bitmap);
				}
			}
		};
	};

应用举例

package com.wei.adapter;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.wei.util.AsyncImageLoader;
import com.wei.util.MyApplication;
import com.wei.util.MyImgCache;
import com.wei.util.MyThread;
import com.wei.util.AsyncImageLoader.LoadFinishCallBack;
import com.wei.wotao.FavorActivity;
import com.wei.wotao.R;
import com.wei.wotao.WebViewActivity;


import android.R.integer;
import android.app.Application;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;


public class FavorAdapter extends BaseAdapter{
	private LayoutInflater mInflater;// 动态布局映射
	private JSONArray list;
	private Context context; 
	GridView gridView;
	private int i = 0;
	AsyncImageLoader asyncImageLoader;
	int itemWidth;
	private String nickname;
	public FavorAdapter(JSONArray list,GridView gridView,Context context,String nickname){
		this.list = list;
		this.context = context;
		this.gridView = gridView;
		this.mInflater = LayoutInflater.from(context);
		itemWidth = MyApplication.screenWidth/2;
		asyncImageLoader  = new AsyncImageLoader();
		this.nickname = nickname;
//		SharedPreferences share = getSharedPreferences("logInfo", 2);
//		nickname = share.getString("username", "");
	}
	public void setList(JSONArray list) {
		this.list = list;
	}
	public JSONArray getList() {
		return list;
	}
	@Override
	public int getCount() {
		// TODO Auto-generated method stub
		return list.length();
	}

	@Override
	public Object getItem(int position) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public long getItemId(int position) {
		// TODO Auto-generated method stub
		return 0;
	}
	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		// TODO Auto-generated method stub
		OneView oneView;
		if (convertView == null) {
			convertView = mInflater.inflate(R.layout.subitem_item_grid_favor2, null);//根据布局文件实例化view
			oneView = new OneView();
			oneView.promotion_price = (TextView) convertView.findViewById(R.id.promotion_price);//找某个控件
			oneView.price = (TextView) convertView.findViewById(R.id.price);
			oneView.sub_price = (TextView) convertView.findViewById(R.id.sub_price);
			oneView.image = (ImageView) convertView.findViewById(R.id.image);
			oneView.remove = (Button) convertView.findViewById(R.id.remove);
			convertView.setTag(oneView);//把View和某个对象关联起来
		} else {
			oneView = (OneView) convertView.getTag();
		}
		JSONObject jObject = null;
		try {
			jObject = list.getJSONObject(position);//根据position获取集合类中某行数据
			oneView.promotion_price.setText("现价¥"+jObject.get("promotion_price").toString());//给该控件设置数据(数据从集合类中来)
			oneView.price.setText("原价¥"+jObject.get("price").toString());
			oneView.price.getPaint().setFlags(Paint. STRIKE_THRU_TEXT_FLAG);
			Float float1 = Float.valueOf(jObject.get("price").toString())- Float.valueOf(jObject.get("promotion_price").toString());
			if (float1 == 0) {
				oneView.sub_price.setVisibility(View.INVISIBLE);
			}
			oneView.sub_price.setText(float1.toString()+" ");
			String strUrl = jObject.get("pic_url").toString() + "_310x310.jpg";
			oneView.image.setTag(strUrl);
			Bitmap bm = asyncImageLoader.asyncLoadImage(strUrl, 0, callback);
			oneView.image.setImageBitmap(null);
			if(bm==null) {
				oneView.image.setBackgroundResource(R.drawable.slt);
			} else {
				oneView.image.setImageBitmap(bm);
			}
			bm = null;
			final String itemID = jObject.get("itemID").toString();
			oneView.remove.setOnClickListener(new View.OnClickListener() {
				@Override
				public void onClick(View v) {
					// TODO Auto-generated method stub
					new MyThread("favor.php?frm=3g&action=favorOrCancel&nickname=" + nickname
							+"&id="+itemID+"&type=sp&favor=0", 0, handler).start();
					Toast.makeText(context, "取消成功"+nickname, 1000).show();
					
				}
			});
		} catch (Exception e) {
			// TODO: handle exception
		}
		return convertView;
	}
	/** 把每行布局文件的各个控件包装成一个对象  */
	private class OneView{
		TextView promotion_price;
		TextView price;
		TextView sub_price;
		ImageView image;
		Button remove;
	}
	//图片下载成功后执行的回调接口
	LoadFinishCallBack callback = new LoadFinishCallBack() {
		@Override
		public void loadFinish(String strUrl, int i, Bitmap bitmap) {
			if (bitmap != null) {
				ImageView imageView = (ImageView) gridView.findViewWithTag(strUrl);
				if(imageView != null) {
					imageView.setImageBitmap(bitmap);
				}
			}
		};
	};
	private Handler handler = new Handler() {
		public void handleMessage(android.os.Message msg) {
			if (msg.what == 0){
				String string = (String) msg.obj;
				if("1".equals(string)){
					Toast.makeText(context, "取消成功", 1000).show();
				}
			}
		};
	};
}



阅读更多
个人分类: Android
上一篇【Android】第三方QQ账号登录的实现
下一篇【Android】App自动更新之通知栏下载
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭