Android 线程

Thread

public class MyThread extends Thread {
    @Override
    public void run() {
        // do something
    }
}

new MyThread().start();

Runnable

// 使用方式1
private class MyRunnable implements Runnable {

    @Override
    public void run() {
        // do something
    }
}

new Thread(new MyRunnable()).start();
// 使用方式2,匿名类的方式更常见些
button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                try {
                   ...
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
});
  • 这种方式仅仅是起动了一个新的线程,没有任务的概念,不能做状态的管理。start之后,run当中的代码就一定会执行到底,无法中途取消。
  • Runnable作为匿名内部类还持有了外部类的引用,在线程退出之前,该引用会一直存在,阻碍外部类对象被GC回收,在一段时间内造成内存泄漏。
  • 没有线程切换的接口,要传递处理结果到UI线程的话,需要写额外的线程切换代码。
  • 如果从UI线程启动,则该线程优先级默认为Default,归于default cgroup,会平等的和UI线程争夺CPU资源。这一点尤其需要注意,在对UI性能要求高的场景下要记得:
    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
    
  • 虽说处于background group的线程总共只能争取到5~10%的CPU资源,但这对绝大部分的后台任务处理都绰绰有余了,1ms和10ms对用户来说,都是快到无法感知,所以我们一般都偏向于在background group当中执行工作线程任务

AsyncTask

button.setOnClickListener(new View.OnClickListener(){ 
 
    @Override 
    public void onClick(View view) { 
        data = null; 
        data = new ArrayList<String>(); 
 
        adapter = null; 
 
        //显示ProgressDialog放到AsyncTask.onPreExecute()里 
        //showDialog(PROGRESS_DIALOG); 
        new ProgressTask().execute(data); 
    } 
}); 
 
private class ProgressTask extends AsyncTask<ArrayList<String>, Void, Integer> { 
 
    /* 该方法将在执行实际的后台操作前被UI thread调用。可以在该方法中做一些准备工作,如在界面上显示一个进度条。*/ 
    @Override 
    protected void onPreExecute() { 
        // 先显示ProgressDialog
        showDialog(PROGRESS_DIALOG); 
    } 
     
    /* 执行那些很耗时的后台计算工作。可以调用publishProgress方法来更新实时的任务进度。 */ 
    @Override 
    protected Integer doInBackground(ArrayList<String>... datas) { 
        ArrayList<String> data = datas[0]; 
        for (int i=0; i<8; i++) { 
            data.add("ListItem"); 
        } 
        return STATE_FINISH; 
    } 
    
    /* 在publishProgress方法被调用后,UI thread将调用这个方法从而在界面上展示任务的进展情况,例如通过一个进度条进行展示 */
    @Override
    protected void onProgressUpdate(Void... values) {

    }
     
    /* 在doInBackground 执行完成后,onPostExecute 方法将被UI thread调用, 
     * 后台的计算结果将通过该方法传递到UI thread. 
     */ 
    @Override 
    protected void onPostExecute(Integer result) { 
        int state = result.intValue(); 
        switch(state){ 
        case STATE_FINISH: 
            dismissDialog(PROGRESS_DIALOG); 
            Toast.makeText(getApplicationContext(), "加载完成!", Toast.LENGTH_LONG).show(); 
     
            adapter = new ArrayAdapter<String>(getApplicationContext(), 
                    android.R.layout.simple_list_item_1, 
                    data );        
            setListAdapter(adapter); 
            break; 
        case STATE_ERROR: 
           dismissDialog(PROGRESS_DIALOG); 
           Toast.makeText(getApplicationContext(), "处理过程发生错误!", Toast.LENGTH_LONG).show();
     
           adapter = new ArrayAdapter<String>(getApplicationContext(), 
                   android.R.layout.simple_list_item_1, 
                   data );
           setListAdapter(adapter);
           break;
       default:
     
    }
}
  • ProgressTask 中4个方法都不能手动调用。而且除了 doInBackground(Params...) 方法,其余3个方法都是被UI线程所调用的,所以要求:
    • AsyncTask的实例必须在UI thread中创建;
    • AsyncTask.execute方法必须在UI thread中调用;
  • 该task只能被执行一次,否则多次调用时将会出现异常。而且是不能手动停止的,这一点要注意,看是否符合需求
  • 在使用过程中,AsyncTask的构造函数的参数设置需要了解
    AsyncTask<Params, Progress, Result>
    Params对应doInBackground(Params...)的参数类型
    而new AsyncTask().execute(Params... params),就是传进来的Params数据
    可以execute(data)来传送一个数据,或者execute(data1, data2, data3)这样多个数据
    
    Progress对应onProgressUpdate(Progress...)的参数类型,表示进度显示单位;
    
    Result对应onPostExecute(Result)的参数类型,表示执行结果的类型
    
    当以上的参数类型都不需要指明某个时,则使用Void,注意不是void
    
  • 和使用Thread()不同的是,多了几处API回调来严格规范工作线程与UI线程之间的交互。我们大部分的业务场景几乎都符合这种规范,比如去磁盘读取图片,缩放处理需要在工作线程执行,最后绘制到ImageView控件需要切换到UI线程。
  • AsyncTask的几处回调都给了我们机会去中断任务,在任务状态的管理上较之Thread()方式更为灵活。值得注意的是AsyncTask的cancel()方法并不会终止任务的执行,开发者需要自己去检查cancel的状态值来决定是否中止任务。
  • AsyncTask也有隐式的持有外部类对象引用的问题,需要特别注意防止出现意外的内存泄漏。
  • AsyncTask由于在不同的系统版本上串行与并行的执行行为不一致,被不少开发者所诟病,这确实是硬伤,绝大部分的多线程场景都需要明确任务是串行还是并行。
  • 线程优先级为background,对UI线程的执行影响极小

Message Queue

  • 在单线程模型下,为了解决类似的问题,Android设计了一个Message Queue(消息队列), 线程间可以通过该Message Queue并结合Handler和Looper组件进行信息交换。下面将对它们进行分别介绍
  • Message
    • Message消息,理解为线程间交流的信息,处理数据后台线程需要更新UI,则发送Message内含一些数据给UI线程。
  • Handler
    • Handler处理者,是Message的主要处理者,负责Message的发送,Message内容的执行处理。后台线程就是通过传进来的Handler对象引用来sendMessage(Message)。而使用Handler,需要implement 该类的 handleMessage(Message)方法,它是处理这些Message的操作内容,例如Update UI。通常需要子类化Handler来实现handleMessage方法。
  • Message Queue
    • Message Queue消息队列,用来存放通过Handler发布的消息,按照先进先出执行。
      每个message queue都会有一个对应的Handler。Handler会向message queue通过两种方法发送消息:sendMessage或post。这两种消息都会插在message queue队尾并按先进先出执行。但通过这两种方法发送的消息执行的方式略有不同:通过sendMessage发送的是一个message对象,会被Handler的handleMessage()函数处理;而通过post方法发送的是一个runnable对象,则会自己执行。
  • Looper
    • Looper是每条线程里的Message Queue的管家。Android没有Global的Message Queue,而Android会自动替主线程(UI线程)建立Message Queue,但在子线程里并没有建立Message Queue。所以调用Looper.getMainLooper()得到的主线程的Looper不为NULL,但调用Looper.myLooper()得到当前线程的Looper就有可能为NULL
      class LooperThread extends Thread {
          public Handler mHandler;
      
          @SuppressLint("HandlerLeak")
          @Override
          public void run() {
              Looper.prepare();   // 创建本线程的Looper并创建一个MessageQueue
      
              mHandler = new Handler() {
                  @Override
                  public void handleMessage(Message msg) {
                      // process incoming messages here
                  }
              };
      
              Looper.loop();  // 开始运行Looper,监听Message Queue
          }
      }
      
  • Message机制的大概流程
    • 在Looper.loop()方法运行开始后,循环地按照接收顺序取出Message Queue里面的非NULL的Message。
    • 一开始Message Queue里面的Message都是NULL的。当Handler.sendMessage(Message)到Message Queue,该函数里面设置了那个Message对象的target属性是当前的Handler对象。随后Looper取出了那个Message,则调用该Message的target指向的Hander的dispatchMessage函数对Message进行处理。在dispatchMessage方法里,如何处理Message则由用户指定,三个判断,优先级从高到低:
      • Message里面的Callback,一个实现了Runnable接口的对象,其中run函数做处理工作;
      • Handler里面的mCallback指向的一个实现了Callback接口的对象,由其handleMessage进行处理;
      • 处理消息Handler对象对应的类继承并实现了其中handleMessage函数,通过这个实现的handleMessage函数处理消息。
      • 由此可见,我们实现的handleMessage方法是优先级最低的!
    • Handler处理完该Message (update UI) 后,Looper则设置该Message为NULL,以便回收

Handler

  • 概念
    • Handler, 它直接继承自Object,一个Handler允许发送和处理Message或者Runnable对象,并且会关联到主线程的MessageQueue 中。每个Handler具有一个单独的线程,并且关联到一个消息队列的线程,就是说一个Handler有一个固有的消息队列。当实例化一个Handler 的时候,它就承载在一个线程和消息队列的线程,这个Handler可以把Message或Runnable压入到消息队列,并且从消息队列中取出 Message或Runnable,进而操作它们
    • Handler可以给线程队列发消息
    • 一个Handler对象只能和一个线程(创造它的线程)关联
  • 创建
    • 使用默认的构造方法:new Handler()
    • 使用带参的构造方法,参数是一个Runnable对象或者回调对象
  • 压入消息队列方法
    • Post:Post允许把一个Runnable对象入队到消息队列中。它的方法有:post(Runnable)postAtTime(Runnable,long)postDelayed(Runnable,long)
    • sendMessage:sendMessage允许把一个包含消息数据的Message对象压入到消息队列中。它的方法 有:sendEmptyMessage(int)sendMessage(Message)sendMessageAtTime(Message, long)sendMessageDelayed(Message, long)
  • 使用Handler的 post 方法
    • 对于Handler的Post方式来说,它会传递一个Runnable对象到消息队列中,在这个Runnable对象中,重写run()方法。一般在这个run()方法中写入需要在UI线程上的操作
    • 在Handler中,关于Post方式的方法有:
      • boolean post(Runnable r):把一个Runnable入队到消息队列中,UI线程从消息队列中取出这个对象后,立即执行。
      • boolean postAtTime(Runnable r, long uptimeMillis):把一个Runnable入队到消息队列中,UI线程从消息队列中取出这个对象后,在特定的时间执行。
      • boolean postDelayed(Runnable r, long delayMillis):把一个Runnable入队到消息队列中,UI线程从消息队列中取出这个对象后,延迟delayMills秒执行
      • void removeCallbacks(Runnable r) :从消息队列中移除一个Runnable对象
    package com.bgxt.datatimepickerdemo;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.os.Handler;
    import android.view.View;
    import android.widget.Button;
    import android.widget.TextView;
    
    public class HandlerPostActivity1 extends Activity {
        private Button btnMes1,btnMes2;
        private TextView tvMessage;
        // 声明一个Handler对象
        private static Handler handler=new Handler();
        
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.message_activity);        
            
            btnMes1=(Button)findViewById(R.id.btnMes1);
            btnMes2=(Button)findViewById(R.id.btnMes2);
            tvMessage=(TextView)findViewById(R.id.tvMessage);
            btnMes1.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    // 新启动一个子线程
                    new Thread(new Runnable() {                    
                        @Override
                        public void run() {
                            // tvMessage.setText("...");
                            // 以上操作会报错,无法再子线程中访问UI组件,UI组件的属性必须在UI线程中访问
                            // 使用post方式修改UI组件tvMessage的Text属性
                            handler.post(new Runnable() {                    
                                @Override
                                public void run() {
                                    tvMessage.setText("使用Handler.post在工作线程中发送一段执行到消息队列中,在主线程中执行。");                        
                                }
                            });                                
                        }
                    }).start();
                }
            });
            
            btnMes2.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    new Thread(new Runnable() {                    
                        @Override
                        public void run() {
                            // 使用postDelayed方式修改UI组件tvMessage的Text属性值
                            // 并且延迟3S执行
                            handler.postDelayed(new Runnable() {
                                @Override
                                public void run() {
                                    tvMessage.setText("使用Handler.postDelayed在工作线程中发送一段执行到消息队列中,在主线程中延迟3S执行。");    
                                }
                            }, 3000);                        
                        }
                    }).start();
                }
            });
        }
    }
    
  • 使用Handler的 Message 方法
    • Handler如果使用sendMessage的方式把消息入队到消息队列中,需要传递一个Message对象,而在Handler中,需要重 写handleMessage()方法,用于获取工作线程传递过来的消息,此方法运行在UI线程上
    • Message是一个final类,所以不可被继承。Message封装了线程中传递的消息,如果对于一般的数据,Message提供了 getData()setData() 方法来获取与设置数据,其中操作的数据是一个Bundle对象,这个Bundle对象提供一系列的getXxx()和setXxx()方法用于传递基本数据类型的键值对,对于基本数据类型,使用起来很简单,这里不再详细讲解。而对于复杂的数据类型,如一个对象的传递就要相对复杂一些。在Bundle中提供了两个方法,专门用来传递对象的,但是这两个方法也有相应的限制,需要实现特定的接口,当然,一些Android自带的类,其实已经实现了这两个接口中的某一个,可以直接使用。方法如下:
      • putParcelable(String key, Parcelable value):需要传递的对象类实现Parcelable接口。
      • pubSerializable(String key, Serializable value):需要传递的对象类实现Serializable接口。
    • 还有另外一种方式在Message中传递对象,那就是使用Message自带的obj属性传值,它是一个Object类型,所以可以传递任意类型的对象,Message自带的有如下几个属性:
      • int arg1:参数一,用于传递不复杂的数据,复杂数据使用setData()传递。
      • int arg2:参数二,用于传递不复杂的数据,复杂数据使用setData()传递。
      • Object obj:传递一个任意的对象。
      • int what:定义的消息码,一般用于设定消息的标志。
    • 对于Message对象,一般并不推荐直接使用它的构造方法得到,而是建议通过使用 Message.obtain() 这个静态的方法或者 Handler.obtainMessage() 获取。Message.obtain() 会从消息池中获取一个Message对象,如果消息池中是空的, 才会使用构造方法实例化一个新Message,这样有利于消息资源的利用。并不需要担心消息池中的消息过多,它是有上限的,上限为10个。 Handler.obtainMessage() 具有多个重载方法,如果查看源码,会发现其实 Handler.obtainMessage() 在内部也是 调用的 Message.obtain()
      public class HandlerMessageActivity1 extends Activity {
          private Button btnDown;
          private ImageView ivImage;
          private static String image_path = "http://ww4.sinaimg.cn/bmiddle/786013a5jw1e7akotp4bcj20c80i3aao.jpg";
          private ProgressDialog dialog;
          private static int IS_FINISH = 1;
      
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.asynctask_activity);
      
              btnDown = (Button) findViewById(R.id.btnDown);
              ivImage = (ImageView) findViewById(R.id.ivSinaImage);
      
              dialog = new ProgressDialog(this);
              dialog.setTitle("提示信息");
              dialog.setMessage("正在下载,请稍后...");
              dialog.setCancelable(false);
      
              btnDown.setOnClickListener(new View.OnClickListener() {
                  @Override
                  public void onClick(View v) {
                          new Thread(new MyThread()).start();
                          dialog.show();
                  }
              });
          }
      
          private  Handler handler = new Handler() {
              // 在Handler中获取消息,重写handleMessage()方法
              @Override
              public void handleMessage(Message msg) {            
                  // 判断消息码是否为1
                  if(msg.what==IS_FINISH){
                      byte[] data=(byte[])msg.obj;
                      Bitmap bmp=BitmapFactory.decodeByteArray(data, 0, data.length);
                      ivImage.setImageBitmap(bmp);
                      dialog.dismiss();
                  }
              }
          };
      
          public class MyThread implements Runnable {
      
              @Override
              public void run() {
                  HttpClient httpClient = new DefaultHttpClient();
                  HttpGet httpGet = new HttpGet(image_path);
                  HttpResponse httpResponse = null;
                  try {
                      httpResponse = httpClient.execute(httpGet);
                      if (httpResponse.getStatusLine().getStatusCode() == 200) {
                          byte[] data = EntityUtils.toByteArray(httpResponse
                                  .getEntity());
                          // 获取一个Message对象,设置what为1
                          Message msg = Message.obtain();
                          msg.obj = data;
                          msg.what = IS_FINISH;
                          // 发送这个消息到消息队列中
                          handler.sendMessage(msg);
                      }
                  } catch (Exception e) {
                      e.printStackTrace();
                  }
              }
          }
      }
      
    • Message.obtain() 方法具有多个重载方法,大致可以分为两类,一类是无需传递Handler对象,对于这类的方法,当填充好消息后,需要调用 Handler.sendMessage() 方法来发送消息到消息队列中。第二类需要传递一个Handler对象,这类方法可以直接使用 Message.sendToTarget() 方法发送消息到消息队列中,这是因为在Message对象中有一个私有的Handler类型的属性 Target ,当时obtain方法传递进一个Handler对象的时候,会给Target属性赋值,当调用 sendToTarget() 方法的时候,实际在它内部还是调用的 Target.sendMessage() 方法。
    • 在Handler中,也定义了一些发送空消息的方法,如:sendEmptyMessage(int what)sendEmptyMessageDelayed(int what,long delayMillis) ,看似这些方法没有使用Message就可以发送一个消息,但是如果查看源码就会发现,其实内部也是从 Message.obtain()方法中获取一个Message对象,然后给属性赋值,最后使用sendMessage()发送消息到消息队列中。
        Handler中,与Message发送消息相关的方法有
      • Message obtainMessage():获取一个Message对象。
      • boolean sendMessage(Message):发送一个Message对象到消息队列中,并在UI线程取到消息后,立即执行。
      • boolean sendMessageDelayed(Message, long):发送一个Message对象到消息队列中,在UI线程取到消息后,延迟执行。
      • boolean sendEmptyMessage(int what):发送一个空的Message对象到队列中,并在UI线程取到消息后,立即执行。
      • boolean sendEmptyMessageDelayed(int what, long delayMillis):发送一个空Message对象到消息队列中,在UI线程取到消息后,延迟执行。
      • void removeMessage():从消息队列中移除一个未响应的消息
      package com.bgxt.datatimepickerdemo;
      
      import android.app.Activity;
      import android.os.Bundle;
      import android.os.Handler;
      import android.os.Message;
      import android.view.View;
      import android.widget.Button;
      import android.widget.TextView;
      
      public class HandlerMessageActivity2 extends Activity {
          private Button btn1, btn2, btn3, btn4,btn5;
          private static TextView tvMes;
          private static Handler handler = new Handler() {
              @Override
              public void handleMessage(android.os.Message msg) {
                  if (msg.what == 3||msg.what==5) {
                      tvMes.setText("what=" + msg.what + ",这是一个空消息");
                  } else {
                      tvMes.setText("what=" + msg.what + "," + msg.obj.toString());
                  }
      
              };
          };
      
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              // TODO Auto-generated method stub
              super.onCreate(savedInstanceState);
              setContentView(R.layout.message_activity2);
              tvMes = (TextView) findViewById(R.id.tvMes);
              btn1 = (Button) findViewById(R.id.btnMessage1);
              btn2 = (Button) findViewById(R.id.btnMessage2);
              btn3 = (Button) findViewById(R.id.btnMessage3);
              btn4 = (Button) findViewById(R.id.btnMessage4);
              btn5 = (Button) findViewById(R.id.btnMessage5);
      
              btn1.setOnClickListener(new View.OnClickListener() {
                  @Override
                  public void onClick(View v) {
                      // 使用Message.Obtain+Hander.sendMessage()发送消息
                      new Thread(new Runnable() {
                          @Override
                          public void run() {
                              Message msg = Message.obtain();
                              msg.what = 1;
                              msg.obj = "使用Message.Obtain+Hander.sendMessage()发送消息";
                              handler.sendMessage(msg);
                          }
                      }).start();
                  }
              });
      
              btn2.setOnClickListener(new View.OnClickListener() {
      
                  @Override
                  public void onClick(View v) {
                      // 使用Message.sendToTarget发送消息
                      new Thread(new Runnable() {
                          @Override
                          public void run() {
                              Message msg = Message.obtain(handler);
                              msg.what = 2;
                              msg.obj = "使用Message.sendToTarget发送消息";
                              msg.sendToTarget();
                          }
                      }).start();
                  }
              });
      
              btn3.setOnClickListener(new View.OnClickListener() {
                  // 发送一个延迟消息
                  @Override
                  public void onClick(View v) {
                      new Thread(new Runnable() {
                          @Override
                          public void run() {
                              handler.sendEmptyMessage(3);
                          }
                      }).start();
                  }
              });
      
              btn4.setOnClickListener(new View.OnClickListener() {
      
                  @Override
                  public void onClick(View v) {
                      new Thread(new Runnable() {
                          @Override
                          public void run() {
                              Message msg = Message.obtain();
                              msg.what =4;
                              msg.obj = "使用Message.Obtain+Hander.sendMessage()发送延迟消息";
                              handler.sendMessageDelayed(msg, 3000);
                          }
                      }).start();
                  }
              });
              
              btn5.setOnClickListener(new View.OnClickListener() {
                  // 发送一个延迟的空消息
                  @Override
                  public void onClick(View v) {
                      new Thread(new Runnable() {
                          @Override
                          public void run() {
                              handler.sendEmptyMessageDelayed(5, 3000);
                          }
                      }).start();
                  }
              });
          }
      }
      

runOnUiThread

public class MainActivity extends AppCompatActivity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        //创建一个线程
        new Thread(new Runnable() {
 
            @Override
            public void run() {
 
                //延迟两秒
                try {
                    Thread.sleep( 2000 );
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
 
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(MainActivity.this, "hah", Toast.LENGTH_SHORT).show();
                    }
                });
 
            }
        }).start();
    }
}

HandlerThread

  • 特点
    • HandlerThread将loop转到子线程中处理,说白了就是将分担MainLooper的工作量,降低了主线程的压力,使主界面更流畅
    • 开启一个线程起到多个线程的作用。处理任务是串行执行,按消息发送顺序进行处理。HandlerThread本质是一个线程,在线程内部,代码是串行处理的。
    • 但是由于每一个任务都将以队列的方式逐个被执行到,一旦队列中有某个任务执行时间过长,那么就会导致后续的任务都会被延迟处理。
    • HandlerThread拥有自己的消息队列,它不会干扰或阻塞UI线程。
    • 对于网络IO操作,HandlerThread并不适合,因为它只有一个线程,还得排队一个一个等着
  • 退出循环
    • quit 方法或 quitSafely 方法
    • 相同点
      • 将不再接受新的事件加入消息队列
      • 无论是调用了quit方法还是quitSafely方法只会,Looper就不再接收新的消息。即在调用了Looper的quit或quitSafely方法之后,消息循环就终结了,这时候再通过Handler调用sendMessage或post等方法发送消息时均返回false,表示消息没有成功放入消息队列MessageQueue中,因为消息队列已经退出了。
    • 不同点
      • 当我们调用Looper的quit方法时,实际上执行了 MessageQueue 中的 removeAllMessagesLocked 方法,该方法的作用是把MessageQueue消息池中所有的消息全部清空,无论是延迟消息(延迟消息是指通过 sendMessageDelayed 或通过 postDelayed 等方法发送的需要延迟执行的消息)还是非延迟消息。
      • 当我们调用Looper的 quitSafely 方法时,实际上执行了MessageQueue中的 removeAllFutureMessagesLocked 方法,通过名字就可以看出,该方法只会清空MessageQueue消息池中所有的延迟消息,并将消息池中所有的非延迟消息派发出去让Handler去处理,quitSafely相比于quit方法安全之处在于清空消息之前会派发所有的非延迟消息。
      • 需要注意的是Looper的quit方法从API Level 1就存在了,但是Looper的quitSafely方法从API Level 18才添加进来
public class MainActivity extends Activity {
    private final static String TAG = "MainActivity";
        
    private Button mGet;
    private TextView mResult;
    
    protected final int MSG_GET = 1;
    protected final int MSG_RESULT = 2;
    
    private HandlerThread mHandlerThread;
    //子线程中的Handler实例。
    private Handler mSubThreadHandler;
    //与Ui线程绑定的Handler实例。
    private Handler mUiHandler = new Handler(){
        public void handleMessage(Message msg) {
            Log.i(TAG, "mUiHandler handleMessage thread:"+Thread.currentThread());
            switch (msg.what) {
            case MSG_RESULT:
                mResult.setText((String)msg.obj);
                break;
            default:
                break;
            }
        };
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.i(TAG, "onCreate thread:"+Thread.currentThread());
        mGet = (Button) findViewById(R.id.get);
        mGet.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                mSubThreadHandler.sendEmptyMessage(MSG_GET);
            }
        });
        mResult = (TextView) findViewById(R.id.result);
        
        initHandlerThraed();
    }
    
    private void initHandlerThraed() {
        //创建HandlerThread实例
        mHandlerThread = new HandlerThread("handler_thread");
        //开始运行线程
        mHandlerThread.start();
        //获取HandlerThread线程中的Looper实例
        Looper loop = mHandlerThread.getLooper();
        //创建Handler与该线程绑定。
        mSubThreadHandler = new Handler(loop){
            public void handleMessage(Message msg) {
                Log.i(TAG, "mSubThreadHandler handleMessage thread:"+Thread.currentThread());
                switch(msg.what){
                case MSG_GET:
                    try { //模拟延时处理
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    double number = Math.random();
                    String result = "number:"+number;
                    //向ui线程发送消息,更新ui。
                    Message message = new Message();
                    message.what = MSG_RESULT;
                    message.obj = result;
                    mUiHandler.sendMessage(message);
                    break;
                default:
                    break;
                }
            };
        };
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.i(TAG, "onDestroy");
        //退出HandlerThread的Looper循环。
        mHandlerThread.quit();
    }
}

ThreadPoolExecutor

  • Thread(), AsyncTask适合处理单个任务的场景,HandlerThread适合串行处理多任务的场景。当需要并行的处理多任务之时,ThreadPoolExecutor 是更好的选择
  • ThreadPoolExecutor 提供了一组线程池,可以管理多个线程并行执行。这样一方面减少了每个并行任务独自建立线程的开销,另一方面可以管理多个并发线程的公共资源,从而提高了多线程的效率。所以 ThreadPoolExecutor 比较适合一组任务的执行。Executors 利用工厂模式对 ThreadPoolExecutor 进行了封装,使用起来更加方便
  • Executors提供了四种创建ExecutorService的方法
    1. Executors.newFixedThreadPool()
       创建一个定长的线程池,每提交一个任务就创建一个线程,直到达到池的最大长度,这时线程池会保持长度不再变化
    2. Executors.newCachedThreadPool()
       创建一个可缓存的线程池,如果当前线程池的长度超过了处理的需要时,它可以灵活的回收空闲的线程,当需要增加时,它可以灵活的添加新的线程,而不会对池的长度作任何限制
    3. Executors.newScheduledThreadPool()
       创建一个定长的线程池,而且支持定时的以及周期性的任务执行,类似于Timer
    4. Executors.newSingleThreadExecutor()
       创建一个单线程化的executor,它只创建唯一的worker线程来执行任务
    
  • 线程池可以避免线程的频繁创建和销毁,显然性能更好,但线程池并发的特性往往也是疑难杂症的源头,是代码降级和失控的开始。多线程并行导致的bug往往是偶现的,不方便调试,一旦出现就会耗掉大量的开发精力。
  • ThreadPool较之HandlerThread在处理多任务上有更高的灵活性,但也带来了更大的复杂度和不确定性

IntentService

  • IntentService 又是另一种开工作线程的方式,从名字就可以看出这个工作线程会带有service的属性。和AsyncTask不同,没有和UI线程的交互,也不像HandlerThread的工作线程会一直存活。IntentService 背后其实也有一个HandlerThread来串行的处理Message Queue,从IntentService的onCreate方法可以看出
    @Override
    public void onCreate() {
        // TODO: It would be nice to have an option to hold a partial wakelock
        // during processing, and to have a static startService(Context, Intent)
        // method that would launch the service & hand off a wakelock.
    
        super.onCreate();
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();
    
        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }
    
    
  • 只不过在所有的Message处理完毕之后,工作线程会自动结束。所以可以把IntentService看做是Service和HandlerThread的结合体,适合需要在工作线程处理UI无关任务的场景
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值