zoukankan      html  css  js  c++  java
  • 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);
            }
        }
    }
  • 相关阅读:
    vscode安装插件时报错
    css-flex整理
    java学习之路--String类的基本方法
    java学习之路--面试之并发基础
    java学习之路--面试之多线程基础
    java学习之路--多线程实现的方法
    java学习之路--简单基础的面试题
    java学习之路
    jquery中remove()和empty()是区别
    创建html新元素的三种方法
  • 原文地址:https://www.cnblogs.com/zx-blog/p/11835790.html
Copyright © 2011-2022 走看看