前面已經提到過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完了。