转 http://www.eoeandroid.com/thread-210082-1-1.html
Handler+ExecutorService(线程池)+MessageQueue模式 能开线程的个数毕竟是有限的,我们总不能开很多线程,对于手机更是如此。 这个例子是使用线程池。Android拥有与Java相同的ExecutorService实现,我们就来用它。 线程池的基本思想还是一种对象池的思想,开辟一块内存空间,里面存放了众多(未死亡)的线程,池中线程执行调度由池管理器来处理。当有线程任务时,从池中取一个,执行完成后线程对象归池,这样可以避免反复创建线程对象所带来的性能开销,节省了系统的资源。 线程池的信息可以参看这篇文章:Java&Android的线程池-ExecutorService 下面的演示例子是创建一个可重用固定线程数的线程池。 核心代码
01 | package ghj1976.AndroidTest; |
03 | import java.io.IOException; |
05 | import java.util.concurrent.ExecutorService; |
06 | import java.util.concurrent.Executors; |
08 | import android.app.Activity; |
09 | import android.graphics.drawable.Drawable; |
10 | import android.os.Bundle; |
11 | import android.os.Handler; |
12 | import android.os.Message; |
13 | import android.os.SystemClock; |
14 | import android.util.Log; |
15 | import android.widget.ImageView; |
17 | public class MainActivity extends Activity { |
19 | public void onCreate(Bundle savedInstanceState) { |
20 | super .onCreate(savedInstanceState); |
21 | setContentView(R.layout.main); |
33 | private Handler handler = new Handler(); |
35 | private ExecutorService executorService = Executors.newFixedThreadPool( 5 ); |
38 | private void loadImage3( final String url, final int id) { |
39 | executorService.submit( new Runnable() { |
42 | final Drawable drawable = Drawable.createFromStream( |
43 | new URL(url).openStream(), "image.png" ); |
45 | SystemClock.sleep( 2000 ); |
46 | handler.post( new Runnable() { |
48 | ((ImageView) MainActivity. this .findViewById(id)) |
49 | .setImageDrawable(drawable); |
52 | } catch (Exception e) { |
53 | throw new RuntimeException(e); |
这里我们象第一步一样使用了 handler.post(new Runnable() { 更新前段显示当然是在UI主线程,我们还有 executorService.submit(new Runnable() { 来确保下载是在线程池的线程中。 Handler+ExecutorService(线程池)+MessageQueue+缓存模式 下面比起前一个做了几个改造:
- 把整个代码封装在一个类中
- 为了避免出现同时多次下载同一幅图的问题,使用了本地缓存
封装的类:
01 | package ghj1976.AndroidTest; |
03 | import java.lang.ref.SoftReference; |
05 | import java.util.HashMap; |
07 | import java.util.concurrent.ExecutorService; |
08 | import java.util.concurrent.Executors; |
10 | import android.graphics.drawable.Drawable; |
11 | import android.os.Handler; |
12 | import android.os.SystemClock; |
14 | public class AsyncImageLoader3 { |
16 | public Map<String, SoftReference<Drawable>> imageCache = new HashMap<String, SoftReference<Drawable>>(); |
18 | private ExecutorService executorService = Executors.newFixedThreadPool( 5 ); |
19 | private final Handler handler = new Handler(); |
29 | public Drawable loadDrawable( final String imageUrl, |
30 | final ImageCallback callback) { |
32 | if (imageCache.containsKey(imageUrl)) { |
33 | SoftReference<Drawable> softReference = imageCache.get(imageUrl); |
34 | if (softReference.get() != null ) { |
35 | return softReference.get(); |
39 | executorService.submit( new Runnable() { |
42 | final Drawable drawable = loadImageFromUrl(imageUrl); |
44 | imageCache.put(imageUrl, new SoftReference<Drawable>( |
47 | handler.post( new Runnable() { |
49 | callback.imageLoaded(drawable); |
52 | } catch (Exception e) { |
53 | throw new RuntimeException(e); |
61 | protected Drawable loadImageFromUrl(String imageUrl) { |
64 | SystemClock.sleep( 2000 ); |
66 | return Drawable.createFromStream( new URL(imageUrl).openStream(), |
69 | } catch (Exception e) { |
70 | throw new RuntimeException(e); |
75 | public interface ImageCallback { |
77 | public void imageLoaded(Drawable imageDrawable); |
说明: final参数是指当函数参数为final类型时,你可以读取使用该参数,但是无法改变该参数的值。参看:Java关键字final、static使用总结 这里使用SoftReference 是为了解决内存不足的错误(OutOfMemoryError)的,更详细的可以参看:内存优化的两个类:SoftReference 和 WeakReference 前段调用:
01 | package ghj1976.AndroidTest; |
03 | import android.app.Activity; |
04 | import android.graphics.drawable.Drawable; |
05 | import android.os.Bundle; |
07 | import android.widget.ImageView; |
09 | public class MainActivity extends Activity { |
11 | public void onCreate(Bundle savedInstanceState) { |
12 | super .onCreate(savedInstanceState); |
13 | setContentView(R.layout.main); |
25 | private AsyncImageLoader3 asyncImageLoader3 = new AsyncImageLoader3(); |
28 | private void loadImage4( final String url, final int id) { |
30 | Drawable cacheImage = asyncImageLoader3.loadDrawable(url, |
31 | new AsyncImageLoader3.ImageCallback() { |
33 | public void imageLoaded(Drawable imageDrawable) { |
34 | ((ImageView) findViewById(id)) |
35 | .setImageDrawable(imageDrawable); |
38 | if (cacheImage != null ) { |
39 | ((ImageView) findViewById(id)).setImageDrawable(cacheImage); |
|