筆記:Handler

我一般創(chuàng)建Handler 是這樣創(chuàng)建的

Handler handler = new Handler(new Handler.Callback() { 
   @Override    
    public boolean handleMessage(Message msg) {      
    Log.i("lpc", "----" + Thread.currentThread().getId() + "");    
    return false;    
}});
handler.sendEmptyMessage(0);

這樣寫法在主線程是沒問題的

但如果在子線程中這樣些就會報錯

new Thread(new Runnable() {    
  @Override    
  public void run() {         
  Handler handler = new Handler(new Handler.Callback() { 
       @Override            
       boolean handleMessage(Message msg) {  
       Log.i("lpc", "----" + Thread.currentThread().getId() + ""); 
       return false;            
       }        
  });        
  handler.sendEmptyMessage(0);         
}}).start();

原因是源碼中有這樣一句

mLooper = Looper.myLooper();
if (mLooper == null) {    
    throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()");
}

也就是說mLooper為空導致的,需要在實例化Handler之前加上

Looper.prepare();

但是就很疑惑,在主線程中創(chuàng)建的Handler是在什么時候prepare的呢,最終原來是在ActivityThread中有這樣一段代碼

public static void main(String[] args) {
    ...
    Looper.prepareMainLooper();
    ...
    Looper.loop();
}

prepareMainLooper方法

public static void prepareMainLooper() {    
    prepare(false);    
    synchronized (Looper.class) {        
    if (sMainLooper != null) {            
        throw new IllegalStateException("The main Looper has already been prepared.");        
    }        
    sMainLooper = myLooper();   
}}

ok,加上prepare方法后但是收不到消息,怎么回事?原來還需加上

Looper.loop();

為什么呢,這就需要看下Looper.loop的代碼了

public static void loop() {
    final Looper me = myLooper();
    ...
    final MessageQueue queue = me.mQueue;
    ...
    for (;;) {    
        Message msg = queue.next(); // might block   
        ....
        msg.target.dispatchMessage(msg);
   }
}

因為默認的是主線程的looper,即me對象,一直循環(huán)取的也是主線程中的MessageQueue對象,所以如果是子線程的情況,需要主動調(diào)用下loop方法才行。

在Handler中有send和post方法,這兩個有什么區(qū)別呢

send方法和post方法實際上最終都會走到這個方法里面

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {   
   MessageQueue queue = mQueue;    
    if (queue == null) {        
    RuntimeException e = new RuntimeException(this + " sendMessageAtTime() called with no mQueue");
    Log.w("Looper", e.getMessage(), e);       
    return false;    
}   
   return enqueueMessage(queue, msg, uptimeMillis);
}

區(qū)別是在這里

public final boolean post(Runnable r){   
    return  sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {    
    Message m = Message.obtain();    
    m.callback = r;    
    return m;
}

實際上也是一個Message對象,只不過他的callback的值就是傳入的Runnable,然后在Looper的loop方法中有這樣一句代碼

msg.target.dispatchMessage(msg);

所以最終會走到

public void dispatchMessage(Message msg) {    
    if (msg.callback != null) {        
        handleCallback(msg);    
    } else {
        if (mCallback != null) {            
              if (mCallback.handleMessage(msg)) {
                 return;           
               }        
        }        
        handleMessage(msg);    
    }
}

handleCallBack方法

private static void handleCallback(Message message) {  
     message.callback.run();
}

實際上只是執(zhí)行了run方法,所以post方法能夠?qū)崿F(xiàn)UI的更新。但是注意,這并不是絕對的,run方法的執(zhí)行是在創(chuàng)建此Handler的線程,而這不一定就是主線程。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容