当我们需要从网络加载图片时,最好使用异步加载的方法,新开一个线程,在此线程中执行加载图片的操作,以避免阻塞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); } }