1. 程式人生 > >Android建立子執行緒和回撥主執行緒的幾種方式

Android建立子執行緒和回撥主執行緒的幾種方式

一. 建立子執行緒

   //通過繼承thread
    public class JNThread1 extends Thread {
        public JNThread1(String name){
            super(name);
        }

        @Override
        public void run() {
            Message msg = new Message();
            msg.obj = "I am a message!";
            mHandler.sendMessage(msg);
        }
    }

    //通過實現Runnable介面來建立子執行緒
public class JNThread2 implements Runnable{ public void run() { } }
     JNThread1 thread = new JNThread1("jiang");
        thread.start();

二. 子執行緒回撥主執行緒的方式

1.view.post(Runnable action)

這是我認為最簡單的方法了,比如你在子執行緒獲得了多個數據,需要更新textview顯示這些資料,可以這樣做

textView.post(new Runnable() { 
    @Override
public void run() { textView.setText("更新啦!"); //還可以更新其他的控制元件 } });

這是view自帶的方法,比較簡單,如果你的子執行緒裡可以得到要更新的view的話,可以用此方法進行更新。

view還有一個方法view.postDelayed(Runnable action, long delayMillis)用來延遲傳送。

2,activity.runOnUiThread(Runnable action)

這是我認為第二簡單的方法了,一般我的上下文(context)是大部分類都會傳到的,而這個 context 其實就是我的 MainActivity,我會直接強制轉換成 Activity 然後用activity.runOnUiThread(Runnable action)方法進行更新UI

 /** * 假設該更新方法在子執行緒中執行 * @param context 上下文 * / 
public void update(final Context context) { 
((MainActivity) context).runOnUiThread(new Runnable() {
             @Override public void run() { 
             //已在主執行緒中,可以更新UI
 } 
}

如果沒有上下文(context)怎麼辦?

用view.getContext()可以得到上下文(不過你為什麼不直接用方法一呢?)
跳過context直接用new Activity().runOnUiThread(Runnable action)來切換到主執行緒。

重點內容

3,Handler

Handler 是最常用也是比上面稍微複雜一點的方法。

首先在主執行緒中定義Handler,Handler mainHandler = new Handler();(必須要在主執行緒中定義才能操作主執行緒,如果想在其他地方定義宣告時要這樣寫Handler mainHandler = new Handler(Looper.getMainLooper()),來獲取主執行緒的 Looper 和 Queue )
獲取到 Handler 後就很簡單了,用handler.post(Runnable r)方法把訊息處理放在該 handler 依附的訊息佇列中(也就是主執行緒訊息佇列),這也是為什麼我們第一步一定要獲取主執行緒的 handler,如果在子執行緒中直接宣告 handler,呼叫handler.post(Runnable r)其實還是在子執行緒中呼叫

/

/假設已在子執行緒 Handler mainHandler = new Handler(Looper.getMainLooper()); 
mainHandler.post(new Runnable() { 
    @Override public void run() { 
    //已在主執行緒中,可以更新UI 
    } 
});

其實一般 Handler 是和 Message 一起使用的。

 //假設在主執行緒中 Handler myHandler = new Handler() {
      @Override public void handleMessage(Message msg) { 
      switch(msg.what) { 
      case 0: //xxx操作 
      case 1: //yyy操作 
      break; 
      default: 
      break; 
    } 
 }

之後可以把 mainHandler 當做引數傳遞在各個類之間,當需要更新UI時,可以呼叫sendMessage一系列方法來執行handleMessage裡的操作。

//假設現在在子執行緒了 
//獲取訊息 
Message msg = myHandler.obtainMessage(); msg.what = 0; 
//訊息標識 
//msg.obj 用來提供額外物件引數 
//傳送訊息 
myHandler.sendMessage(msg);

如上程式碼,只是傳送了個訊息標識,並沒有傳其他引數(可以用msg.arg1
和 msg.arg2
用來提供額外int型引數,用msg.obj
用來提供額外物件引數),可以用簡化方法sendEmptyMessage(int what)
來減少不必要的程式碼

myHandler.sendEmptyMessage(0); //其實內部實現還是和上面一樣

sendEmptyMessageAtTime(int what, long uptimeMillis); //定時傳送訊息
sendEmptyMessageDelayed(int what, long delayMillis); //延時傳送空訊息
sendMessageAtFrontOfQueue(Message msg); //最先處理訊息(慎用)
sendMessageAtTime(Message msg, long uptimeMillis); //定時傳送訊息
sendMessageDelayed(Message msg, long delayMillis); //延時傳送訊息