详细解说Android 异步加载图片

jopen 11年前

(1)由于android UI更新支持单一线程原则,所以从网络上取数据并更新到界面上,为了不阻塞主线程首先可能会想到以下方法。


在主线程中new 一个Handler对象,加载图像方法如下所示


private void loadImage(final String url, final int id) {  handler.post(new Runnable() {  public void run() {  Drawable drawable = null;  try {  drawable = Drawable.createFromStream(new URL(url).openStream(), "image.png");  } catch (IOException e) {  }  ((ImageView) LazyLoadImageActivity.this.findViewById(id)).setImageDrawable(drawable);  }  });  }



上面这个方法缺点很显然,经测试,如果要加载多个图片,这并不能实现异步加载,而是等到所有的图片都加载完才一起显示,因为它们都运行在一个线程中。


然后,我们可以简单改进下,将Handler+Runnable模式改为Handler+Thread+Message模式不就能实现同时开启多个线程吗?


(2)在主线程中new 一个Handler对象,代码如下:


final Handler handler2=new Handler(){  @Override  public void handleMessage(Message msg) {  ((ImageView) LazyLoadImageActivity.this.findViewById(msg.arg1)).setImageDrawable((Drawable)msg.obj);  }  };



对应加载图像代码如下:


//采用handler+Thread模式实现多线程异步加载  private void loadImage2(final String url, final int id) {  Thread thread = new Thread(){  @Override  public void run() {  Drawable drawable = null;  try {  drawable = Drawable.createFromStream(new URL(url).openStream(), "image.png");  } catch (IOException e) {  }     Message message= handler2.obtainMessage() ;  message.arg1 = id;  message.obj = drawable;  handler2.sendMessage(message);  }  };  thread.start();  thread = null;  }



这样就简单实现了异步加载了。细想一下,还可以优化的,比如引入线程池、引入缓存等,我们先介绍线程池。


(3)引入ExecutorService接口,于是代码可以优化如下:


在主线程中加入:private ExecutorService executorService = Executors.newFixedThreadPool(5); 
对应加载图像方法更改如下:


// 引入线程池来管理多线程  private void loadImage3(final String url, final int id) {  executorService.submit(new Runnable() {  public void run() {  try {  final Drawable drawable = Drawable.createFromStream(new URL(url).openStream(), "image.png");  handler.post(new Runnable() {     public void run() {  ((ImageView) LazyLoadImageActivity.this.findViewById(id)).setImageDrawable(drawable);  }  });  } catch (Exception e) {  throw new RuntimeException(e);  }  }  });  }