Android使用Handler實現子執行緒與子執行緒、主執行緒之間通訊
今天這篇文章只講一下怎麼使用Handler實現子執行緒與子執行緒之間、子執行緒與主執行緒之間如何進行通訊,關於具體的內部實現因為我也沒研究過,所以這篇文章講不了。
一、子執行緒向主執行緒傳值:
這個實現比較簡單,因為主執行緒自帶Looper機制,所有我們不用建立Looper了,看一下程式碼吧:
首選在主執行緒裡建立一個Handler
1.Handler mHandler = new Handler(){
2.
3. @Override
4. public void handleMessage(Message msg) {
5. super.handleMessage(msg);
6. switch (msg.what) {
7. case 0:
8. //do something,refresh UI;
9. break;
10. default:
11. break;
12. }
13. }
14.
15.};
然後開啟一個子執行緒,在子執行緒裡直接使用Handler傳送訊息即可
new Thread() {
public void run() {
Message message = new Message();
message.obj = "子執行緒傳送的訊息Hi~Hi";
mHandler .sendMessage(message);
};
}.start();
二、主執行緒向子執行緒裡傳送訊息:
主執行緒向子執行緒傳送訊息的話,我們需要在子執行緒裡初始化Looper,並在主執行緒裡建立的Handler引用子執行緒的Looper(Handler中引用的是哪個執行緒的Looper,就在哪個執行緒裡處理訊息),下面看程式碼:
public class ThreadHandlerActivity extends Activity{
//建立子執行緒
class MyThread extends Thread{
private Looper looper;//取出該子執行緒的Looper
public void run() {
Looper.prepare();//建立該子執行緒的Looper
looper = Looper.myLooper();//取出該子執行緒的Looper
Looper.loop();//只要呼叫了該方法才能不斷迴圈取出訊息
}
}
private Handler mHandler;//將mHandler指定輪詢的Looper
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
thread = new MyThread();
thread.start();//千萬別忘記開啟這個執行緒
//下面是主執行緒傳送訊息
mHandler = new Handler(thread.looper){
public void handleMessage(android.os.Message msg) {
Log.d("當前子執行緒是----->",Thread.currentThread()+"");
};
};
mHandler.sendEmptyMessage(1);
}
}
其實這樣就可以達到主執行緒向子執行緒傳送訊息了,然而當我們執行後發現程式會Crash掉,報了一個控制針,這是因為在Handler初始化的時候,thread.looper還沒有初始化,所以會報控制針,這時我們可以讓主執行緒等待一下子執行緒,也可以來一個while迴圈來判斷thread.looper是否初始化完成。不過Android本身還提供了一個方法,那就是HandlerThread:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
tv = new TextView(this);
tv.setText("Handler實驗");
setContentView(tv);
//例項化一個特殊的執行緒HandlerThread,必須給其指定一個名字
HandlerThread thread = new HandlerThread("handler thread");
thread.start();//千萬不要忘記開啟這個執行緒
//將mHandler與thread相關聯
mHandler = new Handler(thread.getLooper()){
public void handleMessage(android.os.Message msg) {
Log.d("當前子執行緒是----->", Thread.currentThread()+"");
};
};
mHandler.sendEmptyMessage(1);//傳送訊息
}
這時HandlerMessage所在的執行緒就是HandlerThread 的子執行緒。
然而HandlerThread 所建立處理的子執行緒裡是不能重寫Run()方法的,你寫了以後,會發現,HandlerMessage不執行了,這時因為HandlerMessage本身實現了Run()方法,我們看一下內部實現:
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
在原始碼的第4行,進行了例項化自己的Looper,如果繼續追蹤原始碼翻看其getLooper方法你會發現,如果一個Handler在與HandlerThread進行繫結時,發現Looper為空,Handler則會一直等待直到Looper被創建出來為止,然後才繼續執行後續的程式碼。所以我們重寫了HandlerThread的run方法,肯定就不會去建立Looper物件,那麼繫結的Handler就會永遠處於等待狀態,自然而然就不會執行到HandlerMessage資訊了。這也是為什麼我們要使用HandlerThread這個特殊的執行緒,因為使用這個,我們不必關心多執行緒會混亂,Looper會為空等一系列問題,只要去關心我們要實現的邏輯就行了。
三、子執行緒和子執行緒之間通訊:
其實子執行緒向子執行緒之間通訊,其實就是在一個子執行緒中建立一個Handler,它的回撥自然就在此子執行緒中,然後在另一個子執行緒中呼叫此handler來發送訊息就可以了,不過記得寫上Looper哦,下面看程式碼:
new Thread(new Runnable() {
@Override
public void run() {
String msg;
Looper.prepare();
childHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
System.out.println("這個訊息是從-->>" + msg.obj+ "過來的,在" + "btn的子執行緒當中" + "中執行的");
}
};
Looper.loop();//開始輪循
}
}).start();
其中 Looper.prepare()和Looper.loop()一定不要忘了寫。
然後我們建立第二個子執行緒
new Thread(new Runnable() {
@Override
public void run() {
Looper loop = Looper.myLooper();
Message msg = childHandler.obtainMessage();
msg.obj = "btn2當中子執行緒";
childHandler.sendMessage(msg);
}
}).start();