当我们需要从网络加载图片时,最好使用异步加载的方法,新开一个线程,在此线程中执行加载图片的操作,以避免阻塞UI线程的情况的发生。可以使用继承Thread类或者实现Runnable接口的方式,也可以利用Android中的AsyncTask来实现。当然,很多时候我们会对同一张图片显示多次,如果每一次都重新从网络加载的话,必将耗费更多的时间和网络流量,也会占用更多的内存空间,所以我们可以使用缓存的方法,每一次要使用图片时都先从缓存中查找,如果有就直接拿来使用,没有的话就从网络加载,然后再放入缓存中,那么下一次就可以从缓存中找到了。
此处还使用到了JAVA中的SoftReference类,即软引用,软引用是主要用于内存敏感的高速缓存。在jvm报告内存不足之前会清除所有的软引用,这样以来gc就有可能收集软可及的对象,可能解决内存吃紧问题,避免内存溢出。什么时候会被收集取决于gc的算法和gc运行时可用内存的大小。被 Soft Reference 指到的对象,即使没有任何 Direct
Reference,也不会被清除。一直要到 JVM 内存不足且 没有 Direct Reference 时才会清除,SoftReference 是用来设计 object-cache 之用的。如此一来 SoftReference 不但可以把对象 cache 起来,也不会造成内存不足的错误 (OutOfMemoryError)。
代码如下:
package com.buaa.async;
import java.lang.ref.SoftReference;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
public class AsyncHandler {
private SoftReference<Drawable> softReference;
private Map<String, SoftReference<Drawable>> imagesCache = new HashMap<String, SoftReference<Drawable>>();
public Drawable loadDrawable(final String url, final CallbackImp callbackImp) {
// 一开始同时启动3个线程加载图片,Map中还没放进键url,所以任何一个线程都不会找到缓存,都会在网络加载一次图片。
// 当先完成一个线程之后,再启动别的线程的话,就会去到缓存找到图片对象了。
if (imagesCache.containsKey(url)) {
System.out.println("有缓存");
softReference = imagesCache.get(url);
if (softReference.get() != null) {
return softReference.get();
}
}
final Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
System.out.println("没缓存");
callbackImp.imageLoader((Drawable) msg.obj);
}
};
new Thread() {
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
try {
Drawable drawable = Drawable.createFromStream(
new URL(url).openStream(), "src");
imagesCache.put(url, new SoftReference<Drawable>(drawable));
System.out.println("加入缓存中");
Message message = handler.obtainMessage(0, drawable);
handler.sendMessage(message);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}.start();
return null;
}
public interface ImageCallback {
public void imageLoader(Drawable drawable);
}
}
package com.buaa.async;
import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
public class Async extends Activity {
private String url;
Button button1, button2, button3;
private AsyncHandler handler = new AsyncHandler();
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
button1 = (Button) findViewById(R.id.button1);
button2 = (Button) findViewById(R.id.button2);
button3 = (Button) findViewById(R.id.button3);
url = "http://www.baidu.com/img/baidu_sylogo1.gif";
button1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
loadImage(url, R.id.image1);
}
});
button2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
loadImage(url, R.id.image2);
}
});
button3.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
loadImage(url, R.id.image3);
}
});
}
private void loadImage(final String url, final int id) {
ImageView imageView = (ImageView) findViewById(id);
CallbackImp callbackImp = new CallbackImp(imageView);
Drawable drawable = handler.loadDrawable(url, callbackImp);
if (drawable != null) {
imageView.setImageDrawable(drawable);
}
}
}
package com.buaa.async;
import android.graphics.drawable.Drawable;
import android.widget.ImageView;
import com.buaa.async.AsyncHandler.ImageCallback;
public class CallbackImp implements ImageCallback {
public CallbackImp(ImageView imageView) {
super();
this.imageView = imageView;
}
ImageView imageView;
@Override
public void imageLoader(Drawable drawable) {
// TODO Auto-generated method stub
imageView.setImageDrawable(drawable);
}
}