先看演示:
一個Handler允許你發送和處理消息(Message)以及與一個線程的消息隊列相關的Runnable對象。每個Handler實例都和單個線程以及該線程的消息隊列有關。當你創建了一個新Handler,它就會和創建它的線程/消息隊列綁定,在那以後,它就會傳遞消息以及runnable對象給消息隊列,然後執行它們。
1爲什麼使用Handler
需要使用Handler有兩大主要的原因:
(1)在將來的某個時間點調度處理消息和runnable對象;
(2)將需要執行的操作放到其他線程之中,而不是自己的;
調度處理消息是通過調用post(Runnable), postAtTime(Runnable, long),postDelayed(Runnable, long), sendEmptyMessage(int), sendMessage(Message),sendMessageAtTime(Message, long)和sendMessageDelayed(Message,long)等方法完成的。其中的post版本的方法可以讓你將Runnable對象放進消息隊列;sendMessage版本的方法可以讓你將一個包含有bundle對象的消息對象放進消息隊列,然後交由handleMessage(Message)方法處理。(這個需要你複寫Handler的handleMessage方法)
Handler在實際開發中是很常用的,主要是用來接收子線程發送的數據,然後主線程結合此數據來更新界面UI。
Android應用程序啓動時,他會開啓一個主線程(也就是UI線程),管理界面中的UI控件,進行事件派發,比如說:點擊一個按鈕,Android會分發事件到Button上從而來響應你的操作。但是當你需要執行一個比較耗時的操作的話,例如:進行IO操作,網絡通信等等,若是執行時間超過5s,那麼Android會彈出一個“經典”的ANR無響應對話框,然後提示按“Force quit”或是“Wait”。解決此類問題的方法就是:我們把一些耗時的操作放到子線程中去執行。但因爲子線程涉及到UI更新,而Android主線程是線程不安全的,所以更新UI的操作只能放在主線程中執行,若是放在子線程中執行的話很會出問題。所以這時就需要一種機制:主線程可以發送“命令/任務”給子線程執行,然後子線程反饋執行結果;
若在主線程中實例化一個Handler對象,例如:
Handler mHandler = newHandler();
此時它並沒有新派生一個線程來執行此Handler,而是將此Handler附加在主線程上,故此時若你在Handler中執行耗時操作的話,還是會彈出ANR對話框!
2 例子
下面就Handler的使用舉一些例子,加深理解。
2.1、post版本的Handler
public class MainActivity extends Activity
implements OnClickListener {
private final static String TAG = "HandlerTest";
private final static int DELAY_TIME = 1000;
private Button btnStart;
private Button btnStop;
Context mContext = null;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mContext = this;
Log.i(TAG, "Main thread id = " +
Thread.currentThread().getId());
btnStart = (Button) findViewById(R.id.btn_start);
btnStart.setOnClickListener(this);
btnStop = (Button) findViewById(R.id.btn_stop);
btnStop.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn_start:
mHandler.postDelayed(workRunnable, DELAY_TIME);
break;
case R.id.btn_stop:
mHandler.removeCallbacks(workRunnable);
break;
}
}
Runnable workRunnable = new Runnable() {
int counter = 0;
public void run() {
if (counter++ < 1) {
Log.i(TAG, "workRunnable thread id = " +
Thread.currentThread().getId());
mHandler.postDelayed(workRunnable, DELAY_TIME);
}
}
};
Handler mHandler = new Handler();
}
說明:發現thread id是相同的,這就說明:默認情況下創建的Handler會綁定到主線程上,你不能做太耗時的操作。
2.2 HandlerThread
public class MyThread2 extends Activity {
private Handler handler = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
HandlerThread handlerThread = new HandlerThread("myHandlerThread");
handlerThread.start();
handler = new Handler(handlerThread.getLooper());
handler.post(new MyRunnable());
System.out.println("Oncreate---The Thread id is :"
+ Thread.currentThread().getId());
setContentView(R.layout.main);
}
private class MyRunnable implements Runnable {
public void run() {
System.out.println("Runnable---The Thread is running");
System.out.println("Runnable---The Thread id is :"
+ Thread.currentThread().getId());
try {
Thread.sleep(6000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
在這個demo中,用到了HandlerThread,在HandlerThread對象中可以通過getLooper方法獲取一個Looper對象控制句柄,我們可以將其這個Looper對象映射到一個Handler中去來實現一個線程同步機制。於是就有以下結果;
1:控制檯的輸出: Oncreate---The Thread id is :1
Runnable---The Threadis running
Runnable---The Threadid is :10
2:程序啓動後,我們立刻看到main.xml中的內容。
這樣就達到了多線程的結果
2.3 sendMessage版本的Handler
這裏介紹幾種模型:
2.3.1 默認的Handler
(消息處理隊列掛在主線程上)
public class MainActivity extends Activity
implements OnClickListener {
private final static String TAG = "HandlerTest";
private final static int TASK_BEGIN = 1;
private final static int TASK_1 = 2;
private final static int TASK_2 = 3;
private final static int TASK_END = 4;
private Button btnStart = null;
private Button btnStop = null;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
btnStart = (Button) findViewById(R.id.btn_start);
btnStart.setOnClickListener(this);
btnStop = (Button) findViewById(R.id.btn_stop);
btnStop.setOnClickListener(this);
Log.i(TAG, "[M_TID:" + Thread.currentThread().getId() + "]");
}
Handler mHandler = new Handler() {
// 注意:在各個case後面不能做太耗時的操作,否則出現ANR對話框
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case TASK_BEGIN:
Log.i(TAG, "[H_TID:" +
Thread.currentThread().getId() + "] Get TASK_BEGIN");
break;
case TASK_1:
Log.i(TAG, "[H_TID:" +
Thread.currentThread().getId() + "] Get TASK_1");
break;
case TASK_2:
Log.i(TAG, "[H_TID:" +
Thread.currentThread().getId() + "] Get TASK_2");
break;
case TASK_END:
Log.i(TAG, "[H_TID:" +
Thread.currentThread().getId() + "] Get TASK_END");
finish();
break;
}
super.handleMessage(msg);
}
};
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn_start:
// 啓動任務(消息只有標識,立即投遞)
mHandler.sendEmptyMessage(TASK_BEGIN);
Log.i(TAG, "Send TASK_BEGIN to handler.");
// 開始任務1(在mHandler的消息隊列中獲取一個Message對象,避免重複構造)
Message msg1 = mHandler.obtainMessage(TASK_1);
msg1.obj = "This is task1";
mHandler.sendMessage(msg1);
Log.i(TAG, "Send TASK_1 to handler.");
// 開啓任務2(和上面類似)
Message msg2 = Message.obtain();
msg2.arg1 = 10;
msg2.arg2 = 20;
msg2.what = TASK_2;
mHandler.sendMessage(msg2);
Log.i(TAG, "Send TASK_2 to handler.");
break;
case R.id.btn_stop:
// 結束任務(空消息體,延時2s投遞)
mHandler.sendEmptyMessageDelayed(TASK_END, 2000);
Log.i(TAG, "Send TASK_END to handler.");
break;
}
}
}
2.3.2消息隊列仍綁定在主線程上
在子線程中發送消息。
public class MainActivity extends Activity {
private final static String TAG = "HandlerTest";
private final static int TASK_BEGIN = 1;
private final static int TASK_1 = 2;
private final static int TASK_2 = 3;
private final static int TASK_END = 4;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.i(TAG, "[M_TID:" + Thread.currentThread().getId() + "]" +
"This is in main thread.");
workThread.start();
}
Handler mHandler = new Handler() {
// 注意:在各個case後面不能做太耗時的操作,否則出現ANR對話框
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case TASK_BEGIN:
Log.i(TAG, "[H_TID:" +
Thread.currentThread().getId() + "] Get TASK_BEGIN");
break;
case TASK_1:
Log.i(TAG, "[H_TID:" +
Thread.currentThread().getId() + "] Get TASK_1");
break;
case TASK_2:
Log.i(TAG, "[H_TID:" +
Thread.currentThread().getId() + "] Get TASK_2");
break;
case TASK_END:
Log.i(TAG, "[H_TID:" +
Thread.currentThread().getId() + "] Get TASK_END");
finish();
break;
}
super.handleMessage(msg);
}
};
Thread workThread = new Thread() {
// 你可以在run方法內做任何耗時的操作,然後將結果以消息形式投遞到主線程的消息隊列中
@Override
public void run() {
// 啓動任務(消息只有標識,立即投遞)
mHandler.sendEmptyMessage(TASK_BEGIN);
Log.i(TAG, "[S_TID:" + Thread.currentThread().getId() + "]" +
"Send TASK_START to handler.");
// 開始任務1(在mHandler的消息隊列中獲取一個Message對象,避免重複構造)
Message msg1 = mHandler.obtainMessage(TASK_1);
msg1.obj = "This is task1";
mHandler.sendMessage(msg1);
Log.i(TAG, "[S_TID:" + Thread.currentThread().getId() + "]" +
"Send TASK_1 to handler.");
// 開啓任務2(和上面類似)
Message msg2 = Message.obtain();
msg2.arg1 = 10;
msg2.arg2 = 20;
msg2.what = TASK_2;
mHandler.sendMessage(msg2);
Log.i(TAG, "[S_TID:" + Thread.currentThread().getId() + "]" +
"Send TASK_2 to handler.");
// 結束任務(空消息體,延時2s投遞)
mHandler.sendEmptyMessageDelayed(TASK_END, 2000);
Log.i(TAG, "[S_TID:" + Thread.currentThread().getId() + "]" +
"Send TASK_END to handler.");
}
};
}
2.3.3將消息隊列綁定到子線程上,
主線程只管通過Handler往子線程的消息隊列中投遞消息即可。
public class MainActivity extends Activity {
private final static String TAG = "HandlerTest";
private final static int TASK_BEGIN = 1;
private final static int TASK_1 = 2;
private final static int TASK_2 = 3;
private final static int TASK_END = 4;
private MyHandler mHandler = null;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.i(TAG, "[M_TID:" + Thread.currentThread().getId() + "]" +
"This is in main thread.");
HandlerThread myLooperThread = new HandlerThread("my looper thread");
myLooperThread.start();
Looper looper = myLooperThread.getLooper();
mHandler = new MyHandler(looper);
// 啓動任務(消息只有標識,立即投遞)
mHandler.sendEmptyMessage(TASK_BEGIN);
Log.i(TAG, "[S_ID:" + Thread.currentThread().getId() + "]" +
"Send TASK_START to handler.");
// 開始任務1(在mHandler的消息隊列中獲取一個Message對象,避免重複構造)
Message msg1 = mHandler.obtainMessage(TASK_1);
msg1.obj = "This is task1";
mHandler.sendMessage(msg1);
Log.i(TAG, "[S_ID:" + Thread.currentThread().getId() + "]" +
"Send TASK_1 to handler.");
// 開啓任務2(和上面類似)
Message msg2 = Message.obtain();
msg2.arg1 = 10;
msg2.arg2 = 20;
msg2.what = TASK_2;
mHandler.sendMessage(msg2);
Log.i(TAG, "[S_ID:" + Thread.currentThread().getId() + "]" +
"Send TASK_2 to handler.");
// 結束任務(空消息體,延時2s投遞)
mHandler.sendEmptyMessageDelayed(TASK_END, 2000);
Log.i(TAG, "[S_ID:" + Thread.currentThread().getId() + "]" +
"Send TASK_END to handler.");
}
class MyHandler extends Handler {
public MyHandler(Looper looper) {
super(looper);
}
// 現在在每個case之後,你可以做任何耗時的操作了
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case TASK_BEGIN:
Log.i(TAG, "[H_TID:" +
Thread.currentThread().getId() + "] Get TASK_BEGIN");
break;
case TASK_1:
Log.i(TAG, "[H_TID:" +
Thread.currentThread().getId() + "] Get TASK_1");
break;
case TASK_2:
Log.i(TAG, "[H_TID:" +
Thread.currentThread().getId() + "] Get TASK_2");
break;
case TASK_END:
Log.i(TAG, "[H_TID:" +
Thread.currentThread().getId() + "] Get TASK_END");
finish();
break;
}
super.handleMessage(msg);
}
}
}
3 Demo源碼
package mm.shandong.com.testhandler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
public class TestHandlerActivity extends AppCompatActivity {
TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test_handler);
textView= (TextView) findViewById(R.id.textView);
}
public void createSimpleHandler(View view){
final Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case 1:///一般用16進製表示如0x0001
textView.setText(String.valueOf(msg.arg1));
break;
}
}
};
new Thread(){
@Override
public void run() {
int i=0;
while (i<50){
try {
Thread.sleep(100);
Message msg=new Message();
msg.what=1;
msg.arg1=i;
handler.sendMessage(msg);
i++;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
public void createSimpleHandler2(View view){
final Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case 0x0002:///一般用16進製表示如0x0001
Bundle bundle=msg.getData();
Map map= (Map) bundle.get("map");
String name= (String) map.get("name");
textView.setText(name);
break;
}
}
};
new Thread(){
@Override
public void run() {
int i=0;
while (i<50){
try {
Thread.sleep(100);
Message msg=new Message();
msg.what=0x0002;
Bundle bundle=new Bundle();
Map map=new HashMap<>();
map.put("name","張三"+i);
bundle.putSerializable("map", (Serializable) map);
msg.setData(bundle);
handler.sendMessage(msg);
i++;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
public void createSimpleHandler3(View view){
final Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case 1:///一般用16進製表示如0x0001
Toast.makeText(TestHandlerActivity.this,"這是一條空消息",Toast.LENGTH_SHORT).show();
break;
}
}
};
handler.sendEmptyMessage(1);
}
public void createSimpleHandler4(View view){
final Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case 1:///一般用16進製表示如0x0001
Toast.makeText(TestHandlerActivity.this,"這是延遲發送的一條空消息",Toast.LENGTH_SHORT).show();
break;
}
}
};
handler.sendEmptyMessageDelayed(1,2000);
}
public void createSimpleHandler5(View view){
final Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case 1:///一般用16進製表示如0x0001
Toast.makeText(TestHandlerActivity.this,"這是通過obtainMessage從消息池中得到一條消息併發送," +
""+"參數是:"+msg.arg1,Toast.LENGTH_LONG).show();
break;
}
}
};
Message msg=handler.obtainMessage();
msg.what=1;
msg.arg1=3;
handler.sendMessage(msg);
}
public void createSimpleHandler6(View view){
MThreadNoLooper mThreadNoLooper=new MThreadNoLooper();
mThreadNoLooper.start();
if(mThreadNoLooper.handler!=null){
mThreadNoLooper.handler.sendEmptyMessage(1);
}
}
public void createSimpleHandler7(View view){
MThread mThread=new MThread();
mThread.start();
try {
Thread.sleep(100);
if(mThread.handler!=null){
mThread.handler.sendEmptyMessage(1);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public class MThreadNoLooper extends Thread{
public Handler handler;
@Override
public void run() {
handler=new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case 1:///一般用16進製表示如0x0001
Toast.makeText(TestHandlerActivity.this,"這是子線程中的handler監聽到的消息",Toast.LENGTH_LONG).show();
break;
}
}
};
}
}
public class MThread extends Thread{
public Handler handler;
@Override
public void run() {
Looper.prepare();
handler=new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case 1:///一般用16進製表示如0x0001
Toast.makeText(TestHandlerActivity.this,"這是子線程中的handler監聽到的消息",Toast.LENGTH_LONG).show();
break;
}
}
};
Looper.loop();
}
}
}
本人微博:honey_11
Demo下載
最後,以上例子都來源與android學習手冊,請去360手機助手下載:例子源碼,源碼例子文檔一網打盡。