Handler 原理分析和使用之HandlerThread
前面已经提到过Handler的原理以及Handler的三种用法。这里做一个非常简单的一个总结:
- Handler 是跨线程的Message处理。负责把Message推送到MessageQueue和处理。
- Looper 用来轮询MessageQueue,获取Message 发送给指定的Handler进行处理。
- Looper 需要和线程绑定,绑定那个线程,Handler就会在那个线程处理Message
前两篇文章使用Handler处理的场景是:主线程(UI线程)被子线程更新。即使用主线程的Handler和Looper,在子线程中发Message。然后主线程处理 handlerMessage。
-----------------------------------------------------------------------------------------
下面反过来说,如何从UI线程发消息,让子线程处理。
最为通常的做法是:new Thread().start。起一个线程去完成一个任务,任务完成线程就可以自毙了。当然了如果不需要子线程返回结果,而且只有一个线程,那么这是最简单的了。
另一种方法是SyncTask。实例如下:
1 import android.os.AsyncTask; 2 import android.support.v7.app.AppCompatActivity; 3 import android.os.Bundle; 4 import android.view.View; 5 import android.widget.Button; 6 import android.widget.TextView; 7 8 9 public class MainActivity extends AppCompatActivity implements View.OnClickListener{ 10 11 private TextView myTextView; 12 private Button myButton; 13 private MyAsyncTask myTask; 14 @Override 15 protected void onCreate(Bundle savedInstanceState) { 16 super.onCreate(savedInstanceState); 17 setContentView(R.layout.activity_main); 18 myTextView = (TextView)this.findViewById(R.id.text_view); 19 myButton = (Button)this.findViewById(R.id.post); 20 myButton.setOnClickListener(this); 21 //主线程初始化异步任务 22 myTask = new MyAsyncTask(); 23 //主线程启动异步任务, 24 myTask.execute(10); 25 } 26 27 @Override 28 public void onClick(View v) { 29 //主线程取消异步任务 30 myTask.cancel(true); 31 } 32 33 /** 34 * AsyncTask<T, Q, K> 是异步任务基类 包含三个泛型参数。 35 * T 类型参数为执行异步任务时的参数类型doInBackground(T) 36 * Q 类型参数为执行过程中的参数类型onProgressUpdate(Q) 37 * K 类型参数为执行结束onPostExecute(K)或中取消执行时的类型参数onCancelled(K) 38 */ 39 class MyAsyncTask extends AsyncTask<Integer, Integer, Long>{ 40 41 @Override 42 //执行异步任务核心方法,主语T参数类型 43 protected Long doInBackground(Integer... params) { 44 int size = params[0]; 45 long totalSize = 0l; 46 for(int i = 0; i < size; i++){ 47 totalSize += 10000; 48 publishProgress((int) ((i / (float) size) * 100)); 49 if(isCancelled()){ 50 break; 51 } 52 try { 53 Thread.sleep(1000); 54 } catch (InterruptedException e) { 55 e.printStackTrace(); 56 } 57 } 58 return totalSize; 59 } 60 61 @Override 62 //开始执行异步任务前,更新UI线程。 63 protected void onPreExecute() { 64 myTextView.setText("downLoad start !!"); 65 } 66 67 @Override 68 //执行异步任务中,更新UI线程 69 protected void onProgressUpdate(Integer... values) { 70 int progress = values[0]; 71 myTextView.setText(progress + "%"); 72 } 73 74 @Override 75 //执行异步任务后,更新UI线程 76 protected void onPostExecute(Long aLong) { 77 myTextView.setText("Task finished"); 78 } 79 80 @Override 81 //执行异步任务被取消后,跟新UI线程 82 protected void onCancelled(Long aLong) { 83 myTextView.setText("Task camcelled"); 84 } 85 } 86 }
通过实例可以看出,SyncTask不但可以给主线程提供启动和停止接口,还可以给主线程上报过程。当然了开销也是有的。
实际上这种方式也可以用 Handler 原理分析和使用(一)中的例子实现。
以上都是主线程启动一个子线程完成任务。但是如果要做多个异步任务,该如何实现?
首先,从多个异步任务来考虑,如果还是各自不同的话,先考虑到的是线程池。这个在后面的多线程部分在说明。
还有一种方式就是使用HandlerThread。这个就是通过主线程获取其他线程给HandlerThread发消息,使其完成相关的任务。在例举说明HandlerThread使用之前,先看看以下例子。也是主线程给子线程发消息,让子线程处理任务。
1 import android.os.Handler; 2 import android.os.Looper; 3 import android.os.Message; 4 import android.support.v7.app.AppCompatActivity; 5 import android.os.Bundle; 6 import android.util.Log; 7 import android.view.View; 8 import android.widget.Button; 9 import android.widget.TextView; 10 import java.util.concurrent.ArrayBlockingQueue; 11 import java.util.concurrent.BlockingQueue; 12 13 14 public class MainActivity extends AppCompatActivity implements View.OnClickListener{ 15 16 private TextView myTextView; 17 private Button myButton; 18 private MyThread myThread; 19 private Handler myThreadHandler; 20 private int count = 0; 21 @Override 22 protected void onCreate(Bundle savedInstanceState) { 23 super.onCreate(savedInstanceState); 24 setContentView(R.layout.activity_main); 25 myTextView = (TextView)this.findViewById(R.id.text_view); 26 myButton = (Button)this.findViewById(R.id.post); 27 myButton.setOnClickListener(this); 28 //定义子线程 29 myThread = new MyThread(); 30 //获取子线程的Handler 31 myThreadHandler = myThread.getHandler(); 32 //启动子线程 33 myThread.start(); 34 35 } 36 37 @Override 38 public void onClick(View v) { 39 count++; 40 //通过子线程的Handler,主线程给子线程发送消息(添加任务) 41 myThreadHandler.sendEmptyMessage(count); 42 } 43 44 /** 45 * 子线程 46 */ 47 public class MyThread extends Thread{ 48 public Handler mThreadHandler = null; 49 //任务队列 50 public BlockingQueue<Integer> queue = null; 51 public MyThread(){ 52 super(); 53 queue = new ArrayBlockingQueue<Integer>(20); 54 //获取子线程的Looper 55 Looper mThreadLopper = Looper.myLooper(); 56 //初始化子线程的Handler 57 mThreadHandler = new Handler(mThreadLopper, new Handler.Callback() { 58 @Override 59 //接收到主线程发的任务 60 public boolean handleMessage(Message msg) { 61 //任务添加到队列 62 queue.add(msg.what); 63 return false; 64 } 65 }); 66 } 67 public Handler getHandler(){ 68 return mThreadHandler; 69 } 70 public void run(){ 71 while(true){ 72 try{ 73 //任务的处理 74 int what = queue.take(); 75 Log.e("Test", "Click Button = " + what); 76 }catch(InterruptedException e){ 77 78 } 79 80 } 81 } 82 83 } 84 }
上面的例子说明了两件事情。第一,非主线程有自己的Looper(很多文章说没有),第二Handler可以处理非主线程的任务。实际上上面的例子,使用了sendMessage()方法,其实际上用处并不是很广泛,甚至有些憋屈,本身已经有了一个MessageQueue,为什么还要使用一个ArrayBlockingQueue?
实际上上述的例子,完全可以通过HandlerThread来替代。例子如下
import android.os.Handler; import android.os.HandlerThread; import android.os.Message; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.TextView; public class MainActivity extends AppCompatActivity implements View.OnClickListener{ public TextView myTextView; private Button myButton; private HandlerThread myThread; private Handler myThreadHandler; private int count = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); myTextView = (TextView)this.findViewById(R.id.text_view); myButton = (Button)this.findViewById(R.id.post); myButton.setOnClickListener(this); //初始化HandlerThread myThread = new HandlerThread("handlerThread_test"); //启动HandlerThread myThread.start(); //初始化HandlerThrand的Handler对象 myThreadHandler = new Handler(myThread.getLooper(), new Handler.Callback() { @Override //实现消息处理。 public boolean handleMessage(Message msg) { int what =msg.what; Log.e("Test", "Click Button = " + what); return false; } }); } @Override public void onClick(View v) { count++; //通过Handler给HandlerThread线程发送消息 myThreadHandler.sendEmptyMessage(count); //通过Handler给HandlerThreand发送要执行的任务。 myThreadHandler.post(new Runnable() { @Override public void run() { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } Log.e("Test", "Hello world1"); } }); myThreadHandler.post(new Runnable() { @Override public void run() { Log.e("Test", "Hello world2"); } }); } }
从这个例子不难看出HandlerThread实际上是一个Thread,而这个Thread是负责处理Handler派发的消息和任务。此外值得注意有三点:
第一,只有一个线程来处理各种任务。
第一,执行的任务时有序的。也就是说顺序可以被控制。
第二,可以执行各种自定义的任务。
最后关于HandlerThread的退出:myThread.quit();
HandlerThread与SyncTask相比较,缺少执行过程的反馈。但是执行任务的多样性超过SyncTask。当然了都只启动了一个线程。
HandlerThread与Handler-Thread模式比较,也是缺少执行反馈。但是执行多任务时,HandlerThread却只需要一个线程。
所有的Handler就到这里了。也不经意间把SyncTask拿出来溜了一下。其他两篇
Handler完了。