*一.Android 中多线程应用时的消息模型?
使用Android中消息模型的目的是尽量不要去阻塞主线程,然后给用户一种比较友好的体验。
Android 中消息模型关注对象:
1)Message :数据的载体
2)MessageQueue: 存储多个消息对象
3)Looper:迭代消息队列,取出消息。
4)Handler:发送,处理消息队列中的消息。
二.线程池
线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。
使用线程池的好处:
1.减少在创建和销毁线程上所花的时间以及系统资源的开销
2.如不使用线程池,有可能造成系统创建大量线程而导致消耗完系统内存以及”过度切换.
三:功能实现介绍
实现从网络加载图片资源,放到ImageView控件上进行显示.(为了下次启动app时,快速加载图片,需要加入缓存,加入缓存前进行图片压缩).
public class ImageLoader {
public static final int LOAD_FINISH=101;
public static final int NEW_TASK=102;
public static int Thread_Count;
public static Context c;
public static LruCache<String,Bitmap> memCache;
public static LinkedBlockingDeque<Runnable> taskQueue;
public static ExecutorService exec;
public static Handler pollHandler;
public static Handler uiHandler;
public static Thread pollThread;
public static DiskLruCache diskCache;
public static boolean isFirstTime=true;
public static void init(Context context){
c=context;
Thread_Count=getNumberOfCores();
memCache=new LruCache<String, Bitmap>((int)Runtime.getRuntime().maxMemory()/8){
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getHeight()*value.getWidth();
}
};
try {
diskCache=DiskLruCache.open(directory(), appVersion(), 1, 1024*1024*10);
} catch (IOException e1) {
e1.printStackTrace();
}
taskQueue =new LinkedBlockingDeque<Runnable>();
exec=Executors.newFixedThreadPool(Thread_Count);
uiHandler=new Handler(Looper.getMainLooper()){
@Override
public void handleMessage(Message msg) {
if(msg.what==LOAD_FINISH){
ValueObject vo=(ValueObject) msg.obj;
ImageView iv = vo.iv;
String url = vo.url;
Bitmap bitmap = vo.bitmap;
if(iv.getTag().toString().equals(url)){
iv.setImageBitmap(bitmap);
}
}else{
super.handleMessage(msg);
}
}
};
pollThread=new Thread(){
public void run() {
Looper.prepare();
pollHandler =new Handler(){
public void handleMessage(Message msg) {
if(msg.what==NEW_TASK){
try {
Runnable task = taskQueue.takeFirst();
exec.execute(task);
} catch (Exception e) {
e.printStackTrace();
}
}else{
super.handleMessage(msg);
}
};
};
Looper.loop();
};
};
pollThread.start();
isFirstTime=false;
}
private static int appVersion() {
try {
PackageInfo info = c.getPackageManager().getPackageInfo(c.getPackageName(), 0);
return info.versionCode;
} catch (NameNotFoundException e) {
e.printStackTrace();
}
return 1;
}
private static File directory() {
String path = c.getCacheDir().getPath();
return new File(path,"imageloadercache");
}
public static void loaImage(final String url,final ImageView iv){
if(isFirstTime){
throw new RuntimeException("ImageLoading失败");
}
final String md5url=getMD5(url);
iv.setTag(md5url);
Bitmap bitmap = memCache.get(md5url);
if(bitmap!=null){
Log.d("TAG", "图像从内存中加载");
iv.setImageBitmap(bitmap);
return ;
}
try {
Snapshot snapshot = diskCache.get(md5url);
if(snapshot!=null){
Log.d("TAG", "图像从磁盘中加载");
InputStream in = snapshot.getInputStream(0);
bitmap=BitmapFactory.decodeStream(in);
memCache.put(md5url, bitmap);
iv.setImageBitmap(bitmap);
return;
}
} catch (IOException e1) {
e1.printStackTrace();
}
taskQueue.add(new Runnable() {
@Override
public void run() {
try {
URL u=new URL(url);
HttpURLConnection conn = (HttpURLConnection) u.openConnection();
conn.setRequestMethod("GET");
conn.connect();
InputStream in = conn.getInputStream();
Bitmap bitmap=compress(in,iv);
in.close();
memCache.put(md5url, bitmap);
Editor edit = diskCache.edit(md5url);
OutputStream out = edit.newOutputStream(0);
bitmap.compress(CompressFormat.JPEG, 100, out);
edit.commit();
diskCache.flush();
ValueObject vo=new ValueObject(iv, md5url, bitmap);
Message.obtain(uiHandler, LOAD_FINISH, vo).sendToTarget();
} catch (Exception e) {
e.printStackTrace();
}
}
});
Message.obtain(pollHandler, NEW_TASK).sendToTarget();
}
protected static Bitmap compress(InputStream in, ImageView iv) {
Bitmap bitmap=null;
try {
ByteArrayOutputStream out=new ByteArrayOutputStream();
byte[] buff=new byte[4096];
int len=-1;
while((len=in.read(buff))!=-1){
out.write(buff, 0, len);
}
Options opts=new Options();
opts.inJustDecodeBounds=true;
BitmapFactory.decodeByteArray(out.toByteArray(), 0, out.toByteArray().length, opts);
int width = opts.outWidth;
int height = opts.outHeight;
int width2 = iv.getWidth();
int height2 = iv.getHeight();
if(width2==0||height2==0){
width2 = c.getResources().getDisplayMetrics().widthPixels;
height2 = c.getResources().getDisplayMetrics().heightPixels;
}
int samplesize=1;
if(width*1.0/width2>1||height*1.0/height2>1){
samplesize=(int) Math.ceil(Math.max(width*1.0/width2, height*1.0/height2));
}
opts.inSampleSize=samplesize;
opts.inJustDecodeBounds=false;
bitmap = BitmapFactory.decodeByteArray(out.toByteArray(), 0, out.toByteArray().length, opts);
out.close();
} catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}
private static String getMD5(String url) {
String result="";
try {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(url.getBytes());
byte[] bs = md.digest();
StringBuilder sb=new StringBuilder();
for (byte b : bs) {
String str = Integer.toHexString(b&0xff);
if(str.length()==1){
sb.append("0");
}
sb.append(str);
}
result=sb.toString();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
private static int getNumberOfCores() {
File file=new File("/sys/devices/system/cpu/");
File[] files = file.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String filename) {
if(filename.matches("cpu[0-9]")){
return true;
}else{
return false;
}
}
});
return files.length;
}
private static class ValueObject{
ImageView iv;
String url;
Bitmap bitmap;
public ValueObject(ImageView iv, String url, Bitmap bitmap) {
super();
this.iv = iv;
this.url = url;
this.bitmap = bitmap;
}
}
}