Handler是什麼
handler是Android給我們提供用來更新UI的一套機制,也是一套消息處理機制,我們可以發消息,也可以通過它處理消息
原理(解析異步消息處理機制)
Message | Message是在線程之間傳遞的消息,它可以在內部攜帶少量的信息,用於在不同線程之間交換數據。 |
Handler | Handler主要用於發送和處理消息的,發送消息一般是使用Handler的sendMessage()方法,而發出的消息經過處理後,最終會傳遞到Handler的handlerMessage()方法中 |
MessageQueue | 消息隊列,用於存放所有通過Handler發送的消息。每個線程只有一個MessageQueue對象 |
Looper | Looper是每個線程的MessageQueue的管家,調用Looper的loop()方法後,就會進入到一個無限循環當中,然後每當發現MessageQueue中存在一條消息,就會將他取出,並傳遞到Handler的handlerMessage()方法中。每個線程也只會有一個Looper對象 |
處理過程
- 在主線程創建Handler對象。
- 重寫
handlerMessage()
方法。 - 當子線程需要UI操作時,就創建一個Message對象,並通過Handler將這條消息發出去。
- 這條消息被添加到MessageQueue中等待處理,最後分發回handlerMessage中。
- 由於Handler是在主線程創建的,所以此時handlerMessage()方法也在主線程中運行,於是就可以進行UI操作了。
舉例
利用Handler修改子線程UI,這裏簡單演示修改TextView的文字。
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private TextView show;
public static final int UPDATE_TEXT = 1;
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
//接收,判斷,處理消息
switch (msg.what) {
case UPDATE_TEXT:
show.setText("更改UI");
break;
default:
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//一個Textview,修改文字來達到模擬更改界面UI的效果
show = (TextView) findViewById(R.id.tv_show);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.tv_show:
//開啓線程(這裏是模擬在線程裏要修改UI的情況)
new Thread(new Runnable() {
@Override
public void run() {
//定義一個Message,可以發送給Handler
Message myMessage = new Message();
//用戶定義的消息代碼,以便接收者能夠識別該消息的內容。
myMessage.what = UPDATE_TEXT;
//把myMessage放到消息隊列的末尾,它將在handleMessage(Message)中接收
handler.sendMessage(myMessage);
}
});
default:
break;
}
}
}
給message設置數據
如果你需要發送數據,那麼可以往message裏放一個Bundle類型的數據,如下
//設置數據
Bundle bundle = new Bundle();
bundle.putInt("data1", 1);
bundle.putString("data2", "數據二");
message.setData(bundle);
在handleMessage中將數據取出
//取出數據
int data1 = msg.getData().getInt("data1");
String data2 = msg.getData().getString("data2");
sendEmptyMessage()
如果你不需要設置數據,其實不用像上面例子那樣麻煩,使用sendEmptyMessage()
方法可以一行解決,相當於直接發個msg.what給handler了,可以做個對比。
//方法1用三行代碼
Message myMessage = new Message();
myMessage.what = UPDATE_TEXT;
handler.sendMessage(myMessage);
//方法2只用一行代碼
handler.sendEmptyMessage(UPDATE_TEXT)
Handler+TimerTask(3個步驟)
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
Log.e(TAG, "收到信息");
}
super.handleMessage(msg);
}
};
Timer timer=new Timer();
TimerTask task=new TimerTask(){
@Override
public void run() {
Message message = new Message();
message.what=1;
handler.sendMessage(message);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//延遲5秒發送消息
timer.schedule(task,5000);
}
Handler+Runnable(3個步驟)
Handler handler = new Handler();
Runnable mRunnable = new Runnable() {
@Override
public void run() {
Log.e(TAG, "開始工作");
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//執行任務
handler.post(mRunnable);
}
簡單的循環定時器
每隔一秒執行一次work()
函數
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
Handler handler = new Handler();
Runnable mRunnable = new Runnable() {
@Override
public void run() {
work();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//第一次調用work函數
work();
}
//定義work函數
public void work() {
handler.postDelayed(mRunnable, 1000);
Log.e(TAG, "收到信息");
}
}
HandlerThread
關於HandlerThread的寫了另外一篇,感興趣的可以看下,把耗時的操作放到子線程中去,比如下載文件。而主線程通過收到子線程的各種動態,比如子線程開始下載、子線程下載完成來修改主頁面的UI,可以彈個框提示,或者修改TextView文字等等…傳送~傳送