Android 线程池
时间:2019-11-11
本文章向大家介绍Android 线程池,主要包括Android 线程池使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
Handler+Runnable模式
我们先看一个并不是异步线程加载的例子,使用 Handler+Runnable模式。
这里为何不是新开线程的原因请参看这篇文章:Android Runnable 运行在那个线程 这里的代码其实是在UI 主线程中下载图片的,而不是新开线程。
我们运行下面代码时,会发现他其实是阻塞了整个界面的显示,需要所有图片都加载完成后,才能显示界面。
1 /** 2 * Handler+Thread+Message模式 3 */ 4 public class ThreadPoolActivity extends Activity { 5 6 protected static final String TAG = "@@@ThreadPool1Activity"; 7 8 @Override 9 protected void onCreate(Bundle savedInstanceState) { 10 super.onCreate(savedInstanceState); 11 12 setContentView(R.layout.activity_thread1); 13 14 loadImage("http://www.baidu.com/img/baidu_logo.gif", R.id.imageView1); 15 loadImage("http://www.chinatelecom.com.cn/images/logo_new.gif", 16 R.id.imageView2); 17 loadImage("http://cache.soso.com/30d/img/web/logo.gif", R.id.imageView3); 18 loadImage("http://csdnimg.cn/www/images/csdnindex_logo.gif", 19 R.id.imageView4); 20 loadImage("http://images.cnblogs.com/logo_small.gif", R.id.imageView5); 21 } 22 23 private Handler mHandler = new Handler(); 24 25 private void loadImage(final String url, final int id) { 26 27 mHandler.post(new Runnable() { 28 29 @Override 30 public void run() { 31 32 Drawable tDrawable = null; 33 34 try { 35 36 tDrawable = Drawable.createFromStream( 37 new URL(url).openStream(), "image.png"); 38 } catch (Exception e) { 39 40 Log.e(TAG, e.getMessage()); 41 } 42 43 if (tDrawable == null) { 44 45 Log.e(TAG, "null drawable"); 46 } else { 47 48 Log.e(TAG, "not null drawable"); 49 } 50 51 // 为了测试缓存而模拟的网络延时 52 SystemClock.sleep(2000); 53 54 ((ImageView) ThreadPoolActivity.this.findViewById(id)) 55 .setImageDrawable(tDrawable); 56 } 57 }); 58 } 59 } 60 61 Handler+Thread+Message模式 62 这种模式使用了线程,所以可以看到异步加载的效果。 63 /** 64 * Handler+Thread+Message模式 65 */ 66 public class ThreadPoolActivity1 extends Activity { 67 68 protected static final String TAG = "@@@ThreadPool1Activity"; 69 70 @Override 71 protected void onCreate(Bundle savedInstanceState) { 72 super.onCreate(savedInstanceState); 73 74 setContentView(R.layout.activity_thread1); 75 76 loadImage("http://www.baidu.com/img/baidu_logo.gif", R.id.imageView1); 77 loadImage("http://www.chinatelecom.com.cn/images/logo_new.gif", 78 R.id.imageView2); 79 loadImage("http://cache.soso.com/30d/img/web/logo.gif", R.id.imageView3); 80 loadImage("http://csdnimg.cn/www/images/csdnindex_logo.gif", 81 R.id.imageView4); 82 loadImage("http://images.cnblogs.com/logo_small.gif", R.id.imageView5); 83 } 84 85 private Handler mHandler = new Handler() { 86 87 @Override 88 public void handleMessage(Message msg) { 89 ((ImageView) ThreadPoolActivity1.this.findViewById(msg.arg1)) 90 .setImageDrawable((Drawable) msg.obj); 91 } 92 }; 93 94 private void loadImage(final String url, final int id) { 95 96 Thread tThread = new Thread() { 97 98 @Override 99 public void run() { 100 101 Drawable tDrawable = null; 102 103 try { 104 105 tDrawable = Drawable.createFromStream( 106 new URL(url).openStream(), "image.png"); 107 } catch (Exception e) { 108 109 Log.e(TAG, e.getMessage()); 110 } 111 112 if (tDrawable == null) { 113 114 Log.e(TAG, "null drawable"); 115 } else { 116 117 Log.e(TAG, "not null drawable"); 118 } 119 120 // 为了测试缓存而模拟的网络延时 121 SystemClock.sleep(2000); 122 123 Message message = mHandler.obtainMessage(); 124 message.arg1 = id; 125 message.obj = tDrawable; 126 mHandler.sendMessage(message); 127 } 128 }; 129 130 tThread.start(); 131 } 132 }
Handler+ExecutorService(线程池)+MessageQueue模式
能开线程的个数毕竟是有限的,我们总不能开很多线程,对于手机更是如此。
这个例子是使用线程池。Android 拥有与 Java 相同的 ExecutorService 实现,我们就来用他。
线程池的基本思想还是一种对象池的思想,开辟一块内存空间,里面存放了众多(未死亡)的线程,池中线程执行调度由池管理器来处理。当有线程任务时,从池中取一个,执行完成后线程对象归池,这样可以避免反复创建线程对象所带来的性能开销,节省了系统的资源。
/** * Handler+Thread+Message模式 */ public class ThreadPoolActivity2 extends Activity { protected static final String TAG = "@@@ThreadPool1Activity"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_thread1); loadImage("http://www.baidu.com/img/baidu_logo.gif", R.id.imageView1); loadImage("http://www.chinatelecom.com.cn/images/logo_new.gif", R.id.imageView2); loadImage("http://cache.soso.com/30d/img/web/logo.gif", R.id.imageView3); loadImage("http://csdnimg.cn/www/images/csdnindex_logo.gif", R.id.imageView4); loadImage("http://images.cnblogs.com/logo_small.gif", R.id.imageView5); } private Handler handler = new Handler(); private ExecutorService executorService = Executors.newFixedThreadPool(5); // 引入线程池来管理多线程 private void loadImage(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"); // 模拟网络延时 SystemClock.sleep(2000); handler.post(new Runnable() { public void run() { ((ImageView) ThreadPoolActivity2.this .findViewById(id)) .setImageDrawable(drawable); } }); } catch (Exception e) { throw new RuntimeException(e); } } }); } }
Handler+ExecutorService(线程池)+MessageQueue+缓存模式
下面比起前一个做了几个改造:
把整个代码封装在一个类中
为了避免出现同时多次下载同一幅图的问题,使用了本地缓存
/** * @ClassName: AsyncImageLoader * @author Xiao JinLai * @Date 2015-3-15 下午4:39:07 * @Description:图片缓存类 */ public class AsyncImageLoader { // 为了加快速度,在内存中开启缓存(主要应用于重复图片较多时,或者同一个图片要多次被访问,比如在ListView时来回滚动) public Map<String, SoftReference<Drawable>> mImageCache = new HashMap<String, SoftReference<Drawable>>(); private ExecutorService mEService = Executors.newFixedThreadPool(5); // 固定五个线程来执行任务 private final Handler mHandler = new Handler(); /** * * @param imageUrl * 图像url地址 * @param callback * 回调接口 <a * href="\"http://www.eoeandroid.com/home.php?mod=space&uid=7300\"" * target="\"_blank\"">@return</a> 返回内存中缓存的图像,第一次加载返回null */ public Drawable loadDrawable(final String imageUrl, final ImageCallback callback) { // 如果缓存过就从缓存中取出数据 if (mImageCache.containsKey(imageUrl)) { SoftReference<Drawable> softReference = mImageCache.get(imageUrl); if (softReference.get() != null) { return softReference.get(); } } // 缓存中没有图像,则从网络上取出数据,并将取出的数据缓存到内存中 mEService.submit(new Runnable() { public void run() { try { final Drawable drawable = loadImageFromUrl(imageUrl); mImageCache.put(imageUrl, new SoftReference<Drawable>( drawable)); mHandler.post(new Runnable() { public void run() { callback.imageLoaded(drawable); } }); } catch (Exception e) { throw new RuntimeException(e); } } }); return null; } // 从网络上取数据方法 protected Drawable loadImageFromUrl(String imageUrl) { try { // 测试时,模拟网络延时,实际时这行代码不能有 SystemClock.sleep(2000); return Drawable.createFromStream(new URL(imageUrl).openStream(), "image.png"); } catch (Exception e) { throw new RuntimeException(e); } } // 对外界开放的回调接口 public interface ImageCallback { // 注意 此方法是用来设置目标对象的图像资源 public void imageLoaded(Drawable imageDrawable); } } 说明: final 参数是指当函数参数为 final 类型时,你可以读取使用该参数,但是无法改变该参数的值。参看:Java 关键字 final、static使用总结 这里使用 SoftReference 是为了解决内存不足的错误(OutOfMemoryError)的,更详细的可以参看:内存优化的两个类:SoftReference 和 WeakReference 前段调用: /** * Handler+ExecutorService(线程池)+MessageQueue+缓存模式 */ public class ThreadPoolActivity3 extends Activity { protected static final String TAG = "@@@ThreadPoolActivity3"; private AsyncImageLoader mAILoader = new AsyncImageLoader(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_thread1); loadImage("http://www.baidu.com/img/baidu_logo.gif", R.id.imageView1); loadImage("http://www.chinatelecom.com.cn/images/logo_new.gif", R.id.imageView2); loadImage("http://cache.soso.com/30d/img/web/logo.gif", R.id.imageView3); loadImage("http://csdnimg.cn/www/images/csdnindex_logo.gif", R.id.imageView4); loadImage("http://images.cnblogs.com/logo_small.gif", R.id.imageView5); } // 引入线程池,并引入内存缓存功能,并对外部调用封装了接口,简化调用过程 private void loadImage(final String url, final int id) { // 如果缓存过就会从缓存中取出图像,ImageCallback 接口中方法也不会被执行 Drawable tCacheImage = mAILoader.loadDrawable(url, new AsyncImageLoader.ImageCallback() { @Override public void imageLoaded(Drawable imageDrawable) { // 请参见实现:如果第一次加载url时下面方法会执行 ((ImageView) findViewById(id)) .setImageDrawable(imageDrawable); } }); if (tCacheImage != null) { ((ImageView) findViewById(id)).setImageDrawable(tCacheImage); } } }
原文地址:https://www.cnblogs.com/zx-blog/p/11835790.html
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释