Android Handler

Hanlder簡介

相比于 AsyncTaskHandler類允許準確的控制操作的運行時間,而且還可以多次使用,執行的操作會一直運行,直到被顯示的停止。每個Handler實例都被包含在一個單獨的線程里面。

Handler有兩個主要的用途 :

  1. 確保一些調度信息和任務在未來的某一時刻被執行
  2. 讓一些行為在其他的線程中表現出來

HandlerThread 介紹

HandlerThread類用于創建一個帶有 Looper 的新線程,這個Looper可以用于創建Handler實例,HandlerThread 的實例必須在調用start()方法后才可以使用。

構造方法 :

  1. HandlerThread(String name)
  2. HandlerThread (String name, int priority) //priority 就是線程運行的優先級,由 Process類中的變量 來指定

方法 :

  1. getLooper ()

這個方法用于獲取與該線程相關聯的 Looper,如果該線程沒有開啟,也即未調用 start()方法,那么這個方法會返回一個 null值。如果線程已經開啟,這個方法會被阻塞直到 Looper初始化完成。

  1. getThreadId ()

用于返回線程的標識符

  1. quit ()

停止線程中的Looper,該方法被調用后,任何對Looper 的請求都會失敗。比如,sendMessage(Message)方法會返回false。使用這個方法可能是不安全的,因為在Looper被終止的時候可能還有 Message未被遞交。

  1. quitSafely ()

和上一個方法完成的功能相同,不過這個方法更安全,因為在Looper被終止時,一些未遞交的Message會因為時間的關系不再遞交。

  1. run ()

調用Runnable對象中的run()方法,如果未設置Runnable,就什么也不做。

  1. onLooperPrepared ()

該方法是protected類型的,當我們需要在Looperloop() 方法調用前需要完成一些工作,那么可以復寫這個方法。

Looper 的簡單介紹

Looper類用來為線程運行 消息循環,默認的Threads并不包含一個 message loop,為了創建一個,可以在線程中調用 prepare(),然后調用 loop()去處理messages

官方給出的示例

 class LooperThread extends Thread {
  public Handler mHandler;

  public void run() {
      Looper.prepare();

      mHandler = new Handler() {
          public void handleMessage(Message msg) {
              // process incoming messages here
          }
      };

      Looper.loop();
  }

}

介紹一下Looper 類中的一些方法

  1. Looper getMainLooper ()

獲得應用程序的主Looper,存在于主線程中

  1. Thread getThread ()

返回與該Looper 關聯的 Thread

  1. void loop ()

在線程中運行message queue,與此方法對應的是quit()方法,而且這兩個方法必須同時出現。

  1. Looper myLooper ()

返回與該線程關聯的 Looper,如果該線程沒有關聯 Looper,就返回 null

  1. MessageQueue myQueue ()

返回與該線程關聯的 MessageQueue,如果在未關聯Looper的線程中調用該方法,會拋出NullPointerException

  1. void prepare ()

初始化該線程作為一個Looper

  1. void quit ()
  2. void quitSafely()

功能和上面HandlerThread中介紹的一樣

異步消息處理機制

首先,在主線程中創建一個 Handler,并重寫 handleMessage()方法,然后當子線程需要進行 UI 操作時,就創建一個Message 對象,并通過 Handler 將消息發送出去。之后這條消息會被添加到 MessageQueue的隊列中進行等待,而 Looper 會一直嘗試從 MessageQueue 中取出待處理消息,最后分發回 HandlerhandleMessage() 方法中。由于 Handler是在主線程中創建的,此時的 handleMessage()也會在主線程中得到執行。

一個Message經過一個流程的輾轉,從子線程進入到主線程,從不能更新 UI到可以更新UI,這就是異步消息處理機制的核心思想。

Hanlder 的簡單使用

由于 Handler 中的方法太多,就不逐一介紹了,下面來介紹 幾種給 Handler發送信息的方法。

  1. Message.obtain(mHanlder,FLAG,data).sendToTarget()

創建一個標識為FLAG,數據為 dataMessage,立刻將其發送到 Handler去執行

  1. mHandler.sendEmptyMessage(FLAG)

立刻給 Handler發送一個帶有標識的空消息

  1. mHanlder.sendEmptyMessageAtTime(FLAG,1000)

Handler發送一個簡單的空消息,該消息會在一秒后被遞交給Looper

  1. mHandler.sendEmptyMessageDelayed(FLAG,1000)

效果同上

下面利用 Handler 來更改 UI

public class MainActivity extends AppCompatActivity {
public static final int FLAG = 0;
private Button mButton;
private TextView mTextView;
private Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        if (msg.what == FLAG) {
            mTextView.setText("After Changer");
        }
    }
};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mButton = (Button) findViewById(R.id.start);
    mTextView = (TextView) findViewById(R.id.tx);

    mButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    mHandler.sendEmptyMessage(FLAG);
                }
            }).start();
        }
    });
  }
}

注意,這個時候mHandler使用的是默認Looper,也即 MainLooper,我們也可以通過 HandlerThread來使用自己的Looper執行該操作。

public class MainActivity extends AppCompatActivity implements Handler.Callback {

public static final int FLAG = 0;
private Button mButton;
private TextView mTextView;

private HandlerThread mHandlerThread;
private Handler mHandler;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mHandlerThread = new HandlerThread("MyHandlerThread");
    mHandlerThread.start();
    mHandler = new Handler(mHandlerThread.getLooper(), this);

    mButton = (Button) findViewById(R.id.start);
    mTextView = (TextView) findViewById(R.id.tx);

    mButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    mHandler.sendEmptyMessage(FLAG);
                }
            }).start();
        }
    });

}

@Override
public boolean handleMessage(Message message) {
    if (message.what == FLAG) {
        mTextView.setText("After Change");
    }
    return true;
}

}

這個時候會出現一個錯誤,因為我們自己的Looper 是沒有權限去更新 UI的,如果想要更新UI ,可以在Handler的構造方法中使用 getMainLooper()方法。

以上我們都使用使用默認的mHandlerHandlerThread,我們也可以寫一個類繼承自HandlerThread或者Handler,在自定義的類中可以執行一些耗時任務,因為這個時候所有的任務都是在子線程中執行的,并不會阻塞主線程。

關于 AsyncTaskHandler的選擇,如果不是很頻繁的執行一個操作,而且操作可以在較短時間內完成,使用AsyncTask是十分方便的。如果需要安排操作的時間或者需要快速間隔的執行某操作,Handler 是不錯的選擇。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容