Hanlder簡介
相比于 AsyncTask
,Handler
類允許準確的控制操作的運行時間,而且還可以多次使用,執行的操作會一直運行,直到被顯示的停止。每個Handler
實例都被包含在一個單獨的線程里面。
Handler
有兩個主要的用途 :
- 確保一些調度信息和任務在未來的某一時刻被執行
- 讓一些行為在其他的線程中表現出來
HandlerThread 介紹
HandlerThread
類用于創建一個帶有 Looper
的新線程,這個Looper
可以用于創建Handler
實例,HandlerThread
的實例必須在調用start()
方法后才可以使用。
構造方法 :
- HandlerThread(String name)
- HandlerThread (String name, int priority) //priority 就是線程運行的優先級,由 Process類中的變量 來指定
方法 :
- getLooper ()
這個方法用于獲取與該線程相關聯的 Looper
,如果該線程沒有開啟,也即未調用 start()
方法,那么這個方法會返回一個 null
值。如果線程已經開啟,這個方法會被阻塞直到 Looper
初始化完成。
- getThreadId ()
用于返回線程的標識符
- quit ()
停止線程中的Looper
,該方法被調用后,任何對Looper
的請求都會失敗。比如,sendMessage(Message)
方法會返回false
。使用這個方法可能是不安全的,因為在Looper
被終止的時候可能還有 Message
未被遞交。
- quitSafely ()
和上一個方法完成的功能相同,不過這個方法更安全,因為在Looper
被終止時,一些未遞交的Message
會因為時間的關系不再遞交。
- run ()
調用Runnable
對象中的run()
方法,如果未設置Runnable
,就什么也不做。
- onLooperPrepared ()
該方法是protected
類型的,當我們需要在Looper
的loop()
方法調用前需要完成一些工作,那么可以復寫這個方法。
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
類中的一些方法
- Looper getMainLooper ()
獲得應用程序的主Looper
,存在于主線程中
- Thread getThread ()
返回與該Looper
關聯的 Thread
- void loop ()
在線程中運行message queue
,與此方法對應的是quit()
方法,而且這兩個方法必須同時出現。
- Looper myLooper ()
返回與該線程關聯的 Looper
,如果該線程沒有關聯 Looper
,就返回 null
- MessageQueue myQueue ()
返回與該線程關聯的 MessageQueue
,如果在未關聯Looper
的線程中調用該方法,會拋出NullPointerException
- void prepare ()
初始化該線程作為一個Looper
- void quit ()
- void quitSafely()
功能和上面HandlerThread
中介紹的一樣
異步消息處理機制
首先,在主線程中創建一個 Handler
,并重寫 handleMessage()
方法,然后當子線程需要進行 UI
操作時,就創建一個Message
對象,并通過 Handler
將消息發送出去。之后這條消息會被添加到 MessageQueue
的隊列中進行等待,而 Looper
會一直嘗試從 MessageQueue
中取出待處理消息,最后分發回 Handler
的 handleMessage()
方法中。由于 Handler
是在主線程中創建的,此時的 handleMessage()
也會在主線程中得到執行。
一個Message
經過一個流程的輾轉,從子線程進入到主線程,從不能更新 UI
到可以更新UI
,這就是異步消息處理機制的核心思想。
Hanlder 的簡單使用
由于 Handler
中的方法太多,就不逐一介紹了,下面來介紹 幾種給 Handler
發送信息的方法。
- Message.obtain(mHanlder,FLAG,data).sendToTarget()
創建一個標識為FLAG
,數據為 data
的Message
,立刻將其發送到 Handler
去執行
- mHandler.sendEmptyMessage(FLAG)
立刻給 Handler
發送一個帶有標識的空消息
- mHanlder.sendEmptyMessageAtTime(FLAG,1000)
給 Handler
發送一個簡單的空消息,該消息會在一秒后被遞交給Looper
- 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()
方法。
以上我們都使用使用默認的mHandler
和 HandlerThread
,我們也可以寫一個類繼承自HandlerThread
或者Handler
,在自定義的類中可以執行一些耗時任務,因為這個時候所有的任務都是在子線程中執行的,并不會阻塞主線程。
關于 AsyncTask
和 Handler
的選擇,如果不是很頻繁的執行一個操作,而且操作可以在較短時間內完成,使用AsyncTask
是十分方便的。如果需要安排操作的時間或者需要快速間隔的執行某操作,Handler
是不錯的選擇。