多线程之多线程用法大集合(未整理)

来源:互联网 发布:论坛淘宝客插件 编辑:程序博客网 时间:2024/06/06 02:43

handler.post(r)其实这样并不会新起线程,只是执行的runnable里的run()方法,却没有执行start()方法,所以runnable走的还是UI线程。

1.如果像这样,是可以操作ui,但是run还是走在主线程,见打印出来的Log线程名字是main,说明是主线程。

这就是为什么可以直接在run方法里操作ui,因为它本质还是ui线程

handler.post(new Runnable(){

  public void run(){

  Log.e("当前线程:",Thread.currrentThread.getName());//这里打印de结果会是main

  setTitle("哈哈");

      }

});

2.通过HandlerThread获取到looper却是可以新起线程,但是在这里的run方法里操作ui是不可能的,但是这显然有个缺点,如果你执行多次post(r)方法其实走的还是HandlerThread线程。假如你执行5次,n次,其实还是一次并且它们是串行的。假如下载5张图片,你会看到图片是下完第一张,才会去下第二张。

实践证明,只有是拥有主线程looper的handler才可以操作ui,而在主线程操作ui可以在handler的handlerMessage()方法中操作Ui,也可以在handler的post(r)的run方法里操作Ui.

HandlerThread ht = new HandlerThread("handler thread");

ht.start();

handler = new Handler(ht.getLooper());

handler.post(new Runnable(){//这里run()方法其实还是在等ht.start()调用

  public void run(){

  Log.e("当前线程:",Thread.currrentThread.getName());//这里打印的会是handler thread

  setTitle("哈哈");//这样必定报错

  //android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

      }

});

这样该怎么办呢,呵呵,可以无参构建一个handler。用这个handler来发送消息和处理消息,用上面的handler来开启新线程。

mainHandler = new Handler(){

  protecket void handlerMessage(Message msg){

    setTitle("哈哈");//这样就不会报错啦

  }

}

handler.post(new Runnable(){//这里run()方法其实还是在等ht.start()调用

  public void run(){

  Log.e("当前线程:",Thread.currrentThread.getName());//这里打印的会是handler thread

  mainHandler.sendEmpetMessage();//用mainHandler来发送消息

  //setTitle("哈哈");//这样必定报错

  //android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

      }

});

打印Log:

3.其实第2个方法显得麻烦而且低效,用了2个handler,一个用来发起线程,一个用于处理消息。发起线程的handler必须拥有looper,所以还要实例化一个HanderThread;而处理消息的handler则不需要looper,因为它默认拥有主线程的looper,所以可以在这个handler处理ui。

其实可以只需要实例化一个handler,在主线程里构建一个无参的handler,然后由它发送和处理消息。而创建线程的任务就不用handler了,直接用new Thread(r).start();然后在r的run()方法里面处理逻辑事务。

用这样的模式下载5张图片,你就可能不会看到图片一张挨着一张展示出来,可能第2张先出来,也可能同时出来3张,5条线程很随机的。

复制代码
private void loadImagesByThread(final String url,final int id){//通过Thread来new 出多个线程                new Thread(new Runnable(){            @Override            public void run() {                // TODO Auto-generated method stub                Log.e("当前线程:", ""+Thread.currentThread().getName());                Drawable drawable = null;                try {                    drawable = Drawable.createFromStream(new URL(url).openStream(), "image.gif");                } catch (MalformedURLException e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                } catch (IOException e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                }                Message msg = mainHandler.obtainMessage();                msg.what = 2012;                msg.arg1 = id;                msg.obj = drawable;                msg.sendToTarget();                            }                    }).start();    } 
复制代码

打印Log:

4.AsyncTask

用异步任务架构多任务模型其实也不是很健壮,得创建多个AsyncTask实例。一个AsyncTask仅执行一次,不能重复执行,快餐类的线程,一次用完。

实现AsyncTask子类,最重要的两个方法,一个是doInBackground(params);一个是onPostExecute(result)。在doInBackground()方法里处理耗时事务,并把结果返回,返回的值将在onPostExecute方法作为参数,然后就可以在onPostExecute()把结果展示在ui上面了。

步骤:

①实例化AsyncTask:

实例化AsyncTask然后通过task.exec(pamas);传进去参数,这个参数列表是动态的,可以是一个也可以使多个,长度可变。

  AsyncTask<params,values,reslut>,第一个参数会传进去这个方法doInBackground(params),第二个参数是数据更新的值,第三个是处理事务返回的结果。

②onPreExecute方法:

这个方法没有参数,也没有返回值,可以在这个方法里,做一些提醒。比如show一个Dialog,或者弹个Toast告诉用户开始下载啦。

③doInBackground(params)方法:

进入AsyncTask内部结构,首先将执行reslut doInBackground(params)方法,这个方法将处理耗时事务,exec()的参数将会传进这个方法做参数,而返回值将会作为onPostExecute()的参数。如果要更新进度的话,需执行publicProgress()方法。

④onProgressUpdate(values)方法:

这个方法的参数必须在doInBackground()方法里执行publicProgress()方法,这个方法将会把参数传递进onProgressUpdate()方法里,然后可以在这个方法做一些ui上的更新展示,比如进度条的值就可以通过这个values值动态改变。

⑤onPostExecute(result)方法:

这里就是事务处理完毕的走的方法,doInBackground方法执行的结果将传到这里,如果这个方法返回了数据。在这个方法里可以处理Ui,可以把处理完的数据展示在ui上。比如图片啊,文字啊,一切你想要的结果。

复制代码
private void loadImageByAsyncTask(final String url,final int id){//构建异步任务,这样就不用handler来处理消息了        DownloadTask task = new DownloadTask();        task.execute(""+id,url);//AsyncTask不可重复执行    }        class DownloadTask extends AsyncTask<String,Integer,Drawable>{        int id;        @Override        protected Drawable doInBackground(String... params) {//params保存url和控件id两个数据            // TODO Auto-generated method stub            Log.e("当前线程:", ""+Thread.currentThread().getName());            Drawable drawable = null;            this.id = Integer.parseInt(params[0]);            try {                drawable = Drawable.createFromStream(new URL(params[1]).openStream(), "image.gif");            } catch (MalformedURLException e) {                // TODO Auto-generated catch block                e.printStackTrace();            } catch (IOException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }                        return drawable;        }        @Override        protected void onPostExecute(Drawable result) {            // TODO Auto-generated method stub            super.onPostExecute(result);            ((ImageView)MainActivity.this.findViewById(id)).setImageDrawable(result);        }        @Override        protected void onPreExecute() {            // TODO Auto-generated method stub            super.onPreExecute();        }        @Override        protected void onProgressUpdate(Integer... values) {            // TODO Auto-generated method stub            super.onProgressUpdate(values);        }            }
复制代码

这里打印的log

5.ExecutorServie线程池

通过Executors的静态方法来创建,一般有三种:

1.单线程 :Executors.newSingleThreadExecutor();

2.固定数量线程 :Executors.newFixedThreadPool();

3.动态线程 :Executors.newCachedThreadPool();

这里我们用固定5个线程来应用,使用方法是创建ExecutorService对象,然后执行submit(r)可以发起一个Runnable对象。用线程池来管理的好处是,可以保证系统稳定运行,适用与有大量线程,高工作量的情景下使用,假如要展示1000张图片如果创建1000个线程去加载,保证系统会死掉。用线程池就可以避免这个问题,可以用5个线程轮流执行,5个一组,执行完的线程不直接回收而是等待下次执行,这样对系统的开销就可以减小不少。

复制代码
private void loadImagesByExecutors(final String url,final int id){        service.submit(new Runnable(){                        @Override            public void run() {                // TODO Auto-generated method stub                Log.e("当前线程:", ""+Thread.currentThread().getName());                                try {                    final Drawable drawable  = Drawable.createFromStream(new URL(url).openStream(), "image.gif");                    mainHandler.post(new Runnable(){                        @Override                        public void run() {//这将在主线程运行                            // TODO Auto-generated method stub                            ((ImageView)MainActivity.this.findViewById(id)).setImageDrawable(drawable);                        }                    });                                    } catch (MalformedURLException e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                } catch (IOException e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                }                            }                    });            }
复制代码

Log:

其实可能没有说清楚,第一种不算多线程。

1.loadImagesByHandler()是通过Handler.post()方法,构建两个Handler进行通信。

2.loadImagesByThread(),这个是直接new Thread()发起线程,在主线程的handler处理消息

3.loadImageByAsyncTask(),这个用的是异步任务,所有实现在它的内部结构里,可以在里头操作Ui.

4.loadImagesByExecutors()用的是线程池,使得线程可控,保证稳定运行。

其实常用的就是后三种,第二个用法灵活,简单,但不适宜大数量任务;第三个一般适用于单个任务,一次性任务;第四个一般用于大数量,高密度执行的使用情景,比如批量加载图片,批量下载文件等。

看一眼图吧:

全部源码:

复制代码
  1 package com.bvin.exec;  2   3 import java.io.IOException;  4 import java.net.MalformedURLException;  5 import java.net.URL;  6 import java.util.concurrent.ExecutorService;  7 import java.util.concurrent.Executors;  8   9 import android.app.Activity; 10 import android.graphics.drawable.Drawable; 11 import android.os.AsyncTask; 12 import android.os.Bundle; 13 import android.os.Handler; 14 import android.os.HandlerThread; 15 import android.os.Message; 16 import android.util.Log; 17 import android.view.View; 18 import android.widget.Button; 19 import android.widget.ImageView; 20  21 public class MainActivity extends Activity { 22     /** Called when the activity is first created. */ 23      24     private Handler handler ; 25     private Button bt; 26     private Handler mainHandler = new Handler(){ 27  28         @Override 29         public void handleMessage(Message msg) { 30             // TODO Auto-generated method stub 31             super.handleMessage(msg); 32             if(msg.what == 2012){ 33                 //只要在主线程就可以处理ui  34                 ((ImageView)MainActivity.this.findViewById(msg.arg1)).setImageDrawable((Drawable)msg.obj); 35             } 36         } 37          38          39     }; 40      41     private ExecutorService service = Executors.newFixedThreadPool(5); 42      43     @Override 44     public void onCreate(Bundle savedInstanceState) { 45         super.onCreate(savedInstanceState); 46         setContentView(R.layout.main); 47         initViews(); 48         HandlerThread ht = new HandlerThread("down image thread"); 49         ht.start(); 50         handler = new Handler(ht.getLooper()){//如果有了looper那么这个handler就不可以处理ui了 51  52             @Override 53             public void handleMessage(Message msg) { 54                 // TODO Auto-generated method stub 55                 super.handleMessage(msg); 56                  57                  58             } 59              60         }; 61          62     } 63      64     private void initViews(){ 65          66         bt = (Button)findViewById(R.id.bt); 67         bt.setOnClickListener(new View.OnClickListener() { 68              69             @Override 70             public void onClick(View v) { 71                 // TODO Auto-generated method stub 72                 loadImagesByExecutors("http://news.baidu.com/z/resource/r/image/2012-11-23/23c1625aca99f02c50d8e510383a34e7.jpg",R.id.iv1); 73                 loadImagesByExecutors("http://news.baidu.com/z/resource/r/image/2012-11-23/c4698d97ef6d10722c8e917733c7beb3.jpg",R.id.iv2); 74                 loadImagesByExecutors("http://news.baidu.com/z/resource/r/image/2012-11-23/f332ffe433be2a3112be15f78bff5a40.jpg",R.id.iv3); 75                 loadImagesByExecutors("http://news.baidu.com/z/resource/r/image/2012-11-23/6ff8a9c647a1e80bc602eeda48865d4c.jpg",R.id.iv4); 76                 loadImagesByExecutors("http://news.baidu.com/z/resource/r/image/2012-11-23/f104d069f7443dca52a878d779392874.jpg",R.id.iv5); 77             } 78         }); 79     } 80      81     private void loadImagesByHandler(final String url,final int id){//通过拥有looper的handler.post(runnable),新建线程 82          83          84         handler.post(new Runnable(){//如果handler没有Looper那么它就不能构建新线程了 85  86             @Override 87             public void run() { 88                 // TODO Auto-generated method stub 89                 Log.e("当前线程:", ""+Thread.currentThread().getName()); 90                 Drawable drawable = null; 91                 try { 92                     drawable = Drawable.createFromStream(new URL(url).openStream(), "image.gif"); 93                 } catch (MalformedURLException e) { 94                     // TODO Auto-generated catch block 95                     e.printStackTrace(); 96                 } catch (IOException e) { 97                     // TODO Auto-generated catch block 98                     e.printStackTrace(); 99                 }100                 //SystemClock.sleep(2000);101                 //((ImageView)MainActivity.this.findViewById(id)).setImageDrawable(drawable);102                 Message msg = mainHandler.obtainMessage();103                 msg.what = 2012;104                 msg.arg1 = id;105                 msg.obj = drawable;106                 msg.sendToTarget();107             }108             109         });110         111         112     }113     114     private void loadImagesByThread(final String url,final int id){//通过Thread来new 出多个线程115         116         new Thread(new Runnable(){117 118             @Override119             public void run() {120                 // TODO Auto-generated method stub121                 Log.e("当前线程:", ""+Thread.currentThread().getName());122                 Drawable drawable = null;123                 try {124                     drawable = Drawable.createFromStream(new URL(url).openStream(), "image.gif");125                 } catch (MalformedURLException e) {126                     // TODO Auto-generated catch block127                     e.printStackTrace();128                 } catch (IOException e) {129                     // TODO Auto-generated catch block130                     e.printStackTrace();131                 }132                 Message msg = mainHandler.obtainMessage();133                 msg.what = 2012;134                 msg.arg1 = id;135                 msg.obj = drawable;136                 msg.sendToTarget();137                 138             }139             140         }).start();141     } 142 143     private void loadImageByAsyncTask(final String url,final int id){//构建异步任务,这样就不用handler来处理消息了144         DownloadTask task = new DownloadTask();145         task.execute(""+id,url);//AsyncTask不可重复执行146     }147     148     private void loadImagesByExecutors(final String url,final int id){149         service.submit(new Runnable(){150             151             @Override152             public void run() {153                 // TODO Auto-generated method stub154                 Log.e("当前线程:", ""+Thread.currentThread().getName());155                 156                 try {157                     final Drawable drawable  = Drawable.createFromStream(new URL(url).openStream(), "image.gif");158                     mainHandler.post(new Runnable(){159 160                         @Override161                         public void run() {//这将在主线程运行162                             // TODO Auto-generated method stub163                             ((ImageView)MainActivity.this.findViewById(id)).setImageDrawable(drawable);164                         }165                     });166                     167                 } catch (MalformedURLException e) {168                     // TODO Auto-generated catch block169                     e.printStackTrace();170                 } catch (IOException e) {171                     // TODO Auto-generated catch block172                     e.printStackTrace();173                 }174                 175             }176             177         });178         179     }180     181     class DownloadTask extends AsyncTask<String,Integer,Drawable>{182 183         int id;184         @Override185         protected Drawable doInBackground(String... params) {//params保存url和控件id两个数据186             // TODO Auto-generated method stub187             Log.e("当前线程:", ""+Thread.currentThread().getName());188             Drawable drawable = null;189             this.id = Integer.parseInt(params[0]);190             try {191                 drawable = Drawable.createFromStream(new URL(params[1]).openStream(), "image.gif");192             } catch (MalformedURLException e) {193                 // TODO Auto-generated catch block194                 e.printStackTrace();195             } catch (IOException e) {196                 // TODO Auto-generated catch block197                 e.printStackTrace();198             }199             200             return drawable;201         }202 203         @Override204         protected void onPostExecute(Drawable result) {205             // TODO Auto-generated method stub206             super.onPostExecute(result);207             ((ImageView)MainActivity.this.findViewById(id)).setImageDrawable(result);208         }209 210         @Override211         protected void onPreExecute() {212             // TODO Auto-generated method stub213             super.onPreExecute();214         }215 216         @Override217         protected void onProgressUpdate(Integer... values) {218             // TODO Auto-generated method stub219             super.onProgressUpdate(values);220         }221 222         223     }224 }
复制代码

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 顺丰快递保价后商品出现问题怎么办 未保价快递丢失没有价值证明怎么办 安卓手机谷歌地图怎么用不了怎么办 ae模板版本太高打不开怎么办 苹果手机高德地图信号弱怎么办 网上订好火车票后没赶上火车怎么办 丰巢快递柜没收到短信怎么办 被不同号码骚扰电话打个不停怎么办 手机注册被骚扰电话打个不停怎么办 网贷不停的打骚扰电话怎么办 发改委的可研报告过期了怎么办 买到没有预售证的房子怎么办 网上买的学生票取不出来怎么办 买完学生票发现打折没次数了怎么办 动车晚点方向来反了怎么办 身份证购买高铁票过不了审核怎么办 手机购买高铁票身份核验失败怎么办 在高铁上如果有人占了座位该怎么办 网上买的高铁票改签怎么办 临沂村委会强行征收我的土地怎么办 学籍验证码连续输入三次错误怎么办 社保在上海个税在外地居转户怎么办 父母已经有英国签证孩子的怎么办 营运车辆被撞不肯赔务工费怎么办 欧米茄外壳上装表带的孔穿了怎么办 淘宝上买了电子产品坏了怎么办 研究生人才补助申请期限过了怎么办 一个小孩亲妈愿意养躲起来怎么办 网银转账名字打错了怎么办 百世快递邮东西到长春件丢失怎么办 三色吸顶灯有一色不亮了怎么办 超级试驾车超出取车行政区域怎么办 护士电子化注册激活码搞丢了怎么办 香港地铁地铁错买了特惠票怎么办 湖北软考证书领取没有准考证怎么办 哈罗单车电动车骑着没电了怎么办 招聘线上测评的通行证过期了怎么办 上海落户在国企辞职后户口怎么办 老党员干部档案丢失人以去世怎么办 档案中的年龄有涂改办理退休怎么办 到办理退休不知档案在那怎么办