首頁 >後端開發 >php教程 >HandlerThread源碼詳解之Android實例

HandlerThread源碼詳解之Android實例

php中世界最好的语言
php中世界最好的语言原創
2017-12-20 11:47:191672瀏覽

今天帶給大家的文章是透過實例程式碼分析Android中HandlerThread的用法以及步驟,需要的朋友參考學習下吧。

HandlerThread 簡介:
我們知道Thread執行緒​​是一次性消費品,當Thread執行緒​​執行完一個耗時的任務之後,執行緒就會被自動銷毀了。如果此時我又有一

個耗時任務需要執行,我們必須重新建立執行緒去執行該耗時任務。然而,這樣就存在一個效能問題:多次建立和銷毀執行緒是很耗

系統資源的。為了了解這個問題,我們可以自行建立一個循環執行緒Looper Thread,當有耗時任務投放到該循環執行緒時,執行緒執行耗

時任務,執行完後循環執行緒處於等待狀態,直到下一個新的耗時任務被放進來。這樣一來就避免了多次創建Thread線程導致的

效能問題了。也許你可以自己去建立一個循環線程,但我可以告訴你一個好消息,Aandroid SDK中其實已經有一個循環線程的框架

了。此時你只需要掌握其如何使用的就ok啦!當然就是我們今天的主角HandlerThread!接下來請HandlerThread上場,鼓掌~~

HandlerThread的父類是Thread,因此HandlerThread其實是一個線程,只不過其內部幫你實現了一個Looper的循環而已。那我們

先來了解Handler是怎麼使用的吧!

HandlerThread使用步驟:

1.建立實例物件

HandlerThread handlerThread = new HandlerThread("handlerThread");


以上參數可以任意字串,參數的作用主要是標記目前執行緒的名字。

2.啟動HandlerThread執行緒​​

handlerThread.start();


到此,我們就建構完一個循環執行緒了。那你可能會懷疑,那我怎麼將一個耗時的非同步任務投放到HandlerThread執行緒​​中去執行呢?當然是有辦法的,接下來看第三部。

3.建構循環訊息處理機制

Handler subHandler = new Handler(handlerThread.getLooper(), new Handler.Callback() {
      @Override
      public boolean handleMessage(Message msg) {
        //实现自己的消息处理
        return true;
      }
    });


第三個步驟建立一個Handler對象,將上面HandlerThread中的looper物件最為Handler的參數,然後重寫Handler的Callback介面類別中的

handlerMessage方法來處理耗時任務。

總結:以上三步驟不能亂,必須嚴格依照步驟來。到此,我們就可以呼叫subHandler以傳送訊息的形式傳送耗時任務到執行緒

HandlerThread中去執行。言下之意就是subHandler中Callback介面類別中的handlerMessage方法其實是在工作執行緒中執行的。

HandlerThread實例:

package com.example.handlerthread;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity {
  private Handler mSubHandler;
  private TextView textView;
  private Button button;
 
  private Handler.Callback mSubCallback = new Handler.Callback() {
    //该接口的实现就是处理异步耗时任务的,因此该方法执行在子线程中
    @Override
    public boolean handleMessage(Message msg) {
 
      switch (msg.what) {
      case 0:
        Message msg1 = new Message();
        msg1.what = 0;
        msg1.obj = java.lang.System.currentTimeMillis();
        mUIHandler.sendMessage(msg1);
        break;
 
      default:
        break;
      }
 
      return false;
    }
  };
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
 
    textView = (TextView) findViewById(R.id.textView);
    button = (Button) findViewById(R.id.button);
 
    HandlerThread workHandle = new HandlerThread("workHandleThread");
    workHandle.start();
    mSubHandler = new Handler(workHandle.getLooper(), mSubCallback);
 
    button.setOnClickListener(new OnClickListener() {
 
      @Override
      public void onClick(View v) {
        //投放异步耗时任务到HandlerThread中
        mSubHandler.sendEmptyMessage(0);
      }
    });
 
  }
}


HandlerThread原始碼分析

##HandlerThread

建構方法

/**
 * Handy class for starting a new thread that has a looper. The looper can then be
 * used to create handler classes. Note that start() must still be called.
 */
public class HandlerThread extends Thread {
  //线程优先级
  int mPriority;
  //当前线程id
  int mTid = -1;
  //当前线程持有的Looper对象
  Looper mLooper;
   
  //构造方法
  public HandlerThread(String name) {
    //调用父类默认的方法创建线程
    super(name);
    mPriority = Process.THREAD_PRIORITY_DEFAULT;
  }
  //带优先级参数的构造方法
  public HandlerThread(String name, int priority) {
    super(name);
    mPriority = priority;
  }
...............
}

   


分析:類別開頭就給了一個描述:該類別用於建立一個帶有Looper循環的線程,Looper物件用於建立Handler對象,值得注意的是在創建Handler

物件之前需要呼叫start()方法啟動執行緒。這裡可能有些人會有疑問?為啥需要先呼叫start()方法之後才能建立Handler呢?後面我們會解答。

上面的程式碼註解已經很清楚了,HandlerThread類別有兩個建構方法,不同之處就是設定目前執行緒的優先權參數。你可以根據自己的情況來設定優先

級,也可以使用預設優先級。

HandlerThrad的run方法

public class HandlerThread extends Thread {
 /**
   * Call back method that can be explicitly overridden if needed to execute some
   * setup before Looper loops.
   */
  protected void onLooperPrepared() {
  }
 
  @Override
  public void run() {
    //获得当前线程的id
    mTid = Process.myTid();
    //准备循环条件
    Looper.prepare();
    //持有锁机制来获得当前线程的Looper对象
    synchronized (this) {
      mLooper = Looper.myLooper();
      //发出通知,当前线程已经创建mLooper对象成功,这里主要是通知getLooper方法中的wait
      notifyAll();
    }
    //设置当前线程的优先级
    Process.setThreadPriority(mPriority);
    //该方法实现体是空的,子类可以实现该方法,作用就是在线程循环之前做一些准备工作,当然子类也可以不实现。
    onLooperPrepared();
    //启动loop
    Looper.loop();
    mTid = -1;
  }
}


分析:上述程式碼中的註解已經寫得很清楚了,以上run方法主要作用就是呼叫了Looper. prepare和Looper.loop建構了一個迴圈線程。值得一提的

是,run方法中在啟動loop循環之前呼叫了onLooperPrepared方法,該方法的實作是一個空的,使用者可以在子類別中實作該方法。這個方法的作用是

在執行緒loop之前做一些初始化工作,當然你也可以不實作這個方法,具體看需求。由此也可以看出,Google工程師在編寫程式碼時也考慮到程式碼的可擴展性。牛B!

HandlerThread的其他方法


getLooper取得目前執行緒的Looper物件

/**
   * This method returns the Looper associated with this thread. If this thread not been started
   * or for any reason is isAlive() returns false, this method will return null. If this thread
   * has been started, this method will block until the looper has been initialized.
   * @return The looper.
   */
  public Looper getLooper() {
    //如果线程不是存活的,则直接返回null
    if (!isAlive()) {
      return null;
    }
     
    // If the thread has been started, wait until the looper has been created.
    //如果线程已经启动,但是Looper还未创建的话,就等待,知道Looper创建成功
    synchronized (this) {
      while (isAlive() && mLooper == null) {
        try {
          wait();
        } catch (InterruptedException e) {
        }
      }
    }
    return mLooper;
  }

   


#分析:其實方法開頭的英文註解已經解釋的很清楚了:此方法主要作用是取得目前HandlerThread執行緒​​中的mLooper物件。

先判斷目前執行緒是否存活,如果不是存活的,這直接回傳null。其次如果當前線程存活的,在判斷線程的成員變數mLooper是否為null,如果為

null,說明當前線程已經創建成功,但是還沒來得及創建Looper對象,因此,這裡會調用wait方法去等待,當run方法中的notifyAll方法呼叫之後

通知目前執行緒的wait方法等待結束,跳出循環,獲得mLooper物件的值。

总结:在获得mLooper对象的时候存在一个同步的问题,只有当线程创建成功并且Looper对象也创建成功之后才能获得mLooper的值。这里等待方法wait和run方法中的notifyAll方法共同完成同步问题。

quit结束当前线程的循环

/**
   * Quits the handler thread's looper.
   * <p>
   * Causes the handler thread&#39;s looper to terminate without processing any
   * more messages in the message queue.
   * </p><p>
   * Any attempt to post messages to the queue after the looper is asked to quit will fail.
   * For example, the {@link Handler#sendMessage(Message)} method will return false.
   * </p><p class="note">
   * Using this method may be unsafe because some messages may not be delivered
   * before the looper terminates. Consider using {@link #quitSafely} instead to ensure
   * that all pending work is completed in an orderly manner.
   * </p>
   *
   * @return True if the looper looper has been asked to quit or false if the
   * thread had not yet started running.
   *
   * @see #quitSafely
   */
  public boolean quit() {
    Looper looper = getLooper();
    if (looper != null) {
      looper.quit();
      return true;
    }
    return false;
  }
//安全退出循环
 public boolean quitSafely() {
    Looper looper = getLooper();
    if (looper != null) {
      looper.quitSafely();
      return true;
    }
    return false;
  }

   


分析:以上有两种让当前线程退出循环的方法,一种是安全的,一中是不安全的。至于两者有什么区别? quitSafely方法效率比quit方法标率低一点,但是安全。具体选择哪种就要看具体项目了。

总结:

1.HandlerThread适用于构建循环线程。

2.在创建Handler作为HandlerThread线程消息执行者的时候必须调用start方法之后,因为创建Handler需要的Looper参数是从HandlerThread类中获得,而Looper对象的赋值又是在HandlerThread的run方法中创建。


相信看了这些案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

相关阅读:

php如何实现栈数据结构以及括号匹配算法的代码示例详解

php中最简单的字符串匹配算法,php匹配算法_PHP教程

最简单的php中字符串匹配算法教程

以上是HandlerThread源碼詳解之Android實例的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn