Android使用Handler實現子線程與子線程、子線程與主線程之間通信


轉載:https://blog.csdn.net/shaoenxiao/article/details/54561753

今天這篇文章只講一下怎么使用Handler實現子線程與子線程之間、子線程與主線程之間如何進行通信,關於具體的內部實現因為我也沒研究過,所以這篇文章講不了。

一、子線程向主線程傳值:

這個實現比較簡單,因為主線程自帶Looper機制,所有我們不用創建Looper了,看一下代碼吧:

首選在主線程里創建一個Handler

  1. 1.Handler mHandler = new Handler(){
  2. 2.
  3. 3. @Override
  4. 4. public void handleMessage(Message msg) {
  5. 5. super.handleMessage(msg);
  6. 6. switch (msg.what) {
  7. 7. case 0:
  8. 8. //do something,refresh UI;
  9. 9. break;
  10. 10. default:
  11. 11. break;
  12. 12. }
  13. 13. }
  14. 14.
  15. 15.};

然后開啟一個子線程,在子線程里直接使用Handler發送消息即可

  1. new Thread() {
  2. public void run() {
  3. Message message = new Message();
  4. message.obj = "子線程發送的消息Hi~Hi";
  5. mHandler .sendMessage(message);
  6. };
  7. }.start();

二、主線程向子線程里發送消息:

主線程向子線程發送消息的話,我們需要在子線程里初始化Looper,並在主線程里創建的Handler引用子線程的Looper(Handler中引用的是哪個線程的Looper,就在哪個線程里處理消息),下面看代碼:

  1. public class ThreadHandlerActivity extends Activity{
  2. //創建子線程
  3. class MyThread extends Thread{
  4. private Looper looper;//取出該子線程的Looper
  5. public void run() {
  6.  
  7. Looper.prepare(); //創建該子線程的Looper
  8. looper = Looper.myLooper(); //取出該子線程的Looper
  9. Looper.loop(); //只要調用了該方法才能不斷循環取出消息
  10. }
  11. }
  12.  
  13. private Handler mHandler;//將mHandler指定輪詢的Looper
  14.  
  15. protected void onCreate(Bundle savedInstanceState) {
  16. super.onCreate(savedInstanceState);
  17. setContentView(R.layout.main);
  18. thread = new MyThread();
  19. thread.start(); //千萬別忘記開啟這個線程
  20. //下面是主線程發送消息
  21. mHandler = new Handler(thread.looper){
  22. public void handleMessage(android.os.Message msg) {
  23. Log.d( "當前子線程是----->",Thread.currentThread()+"");
  24. };
  25. };
  26. mHandler.sendEmptyMessage( 1);
  27. }
  28.  
  29. }

其實這樣就可以達到主線程向子線程發送消息了,然而當我們運行后發現程序會Crash掉,報了一個控制針,這是因為在Handler初始化的時候,thread.looper還沒有初始化,所以會報控制針,這時我們可以讓主線程等待一下子線程,也可以來一個while循環來判斷thread.looper是否初始化完成。不過Android本身還提供了一個方法,那就是HandlerThread

  1. protected void onCreate(Bundle savedInstanceState) {
  2. super.onCreate(savedInstanceState);
  3. tv = new TextView(this);
  4. tv.setText( "Handler實驗");
  5. setContentView(tv);
  6.  
  7. //實例化一個特殊的線程HandlerThread,必須給其指定一個名字
  8. HandlerThread thread = new HandlerThread("handler thread");
  9. thread.start(); //千萬不要忘記開啟這個線程
  10. //將mHandler與thread相關聯
  11. mHandler = new Handler(thread.getLooper()){
  12. public void handleMessage(android.os.Message msg) {
  13. Log.d( "當前子線程是----->", Thread.currentThread()+"");
  14. };
  15. };
  16. mHandler.sendEmptyMessage( 1);//發送消息
  17. }

這時HandlerMessage所在的線程就是HandlerThread 的子線程。
然而HandlerThread 所創建處理的子線程里是不能重寫Run()方法的,你寫了以后,會發現,HandlerMessage不執行了,這時因為HandlerMessage本身實現了Run()方法,我們看一下內部實現:

  1. @Override
  2. public void run() {
  3. mTid = Process.myTid();
  4. Looper.prepare();
  5. synchronized (this) {
  6. mLooper = Looper.myLooper();
  7. notifyAll();
  8. }
  9. Process.setThreadPriority(mPriority);
  10. onLooperPrepared();
  11. Looper.loop();
  12. mTid = - 1;
  13. }

在源代碼的第4行,進行了實例化自己的Looper,如果繼續追蹤源代碼翻看其getLooper方法你會發現,如果一個Handler在與HandlerThread進行綁定時,發現Looper為空,Handler則會一直等待直到Looper被創建出來為止,然后才繼續執行后續的代碼。所以我們重寫了HandlerThread的run方法,肯定就不會去創建Looper對象,那么綁定的Handler就會永遠處於等待狀態,自然而然就不會執行到HandlerMessage信息了。這也是為什么我們要使用HandlerThread這個特殊的線程,因為使用這個,我們不必關心多線程會混亂,Looper會為空等一系列問題,只要去關心我們要實現的邏輯就行了。

三、子線程和子線程之間通信:

其實子線程向子線程之間通信,其實就是在一個子線程中創建一個Handler,它的回調自然就在此子線程中,然后在另一個子線程中調用此handler來發送消息就可以了,不過記得寫上Looper哦,下面看代碼:

  1. new Thread(new Runnable() {
  2.  
  3. @Override
  4. public void run() {
  5. String msg;
  6. Looper.prepare();
  7.  
  8. childHandler = new Handler() {
  9. @Override
  10. public void handleMessage(Message msg) {
  11. super.handleMessage(msg);
  12.  
  13. System.out.println( "這個消息是從-->>" + msg.obj+ "過來的,在" + "btn的子線程當中" + "中執行的");
  14.  
  15. }
  16.  
  17. };
  18. Looper.loop(); //開始輪循
  19.  
  20. }
  21. }).start();

其中 Looper.prepare()和Looper.loop()一定不要忘了寫。

然后我們創建第二個子線程

    1. new Thread(new Runnable() {
    2.  
    3. @Override
    4. public void run() {
    5. Looper loop = Looper.myLooper();
    6. Message msg = childHandler.obtainMessage();
    7. msg.obj = "btn2當中子線程";
    8. childHandler.sendMessage(msg);
    9. }
    10. }).start();


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM