天天看點

Hanlder的使用及其Looper,MessageQueue原理

Handler是Android中的消息處理機制,多用于線程之間傳遞消息。

一.使用方法

final Handler mHandler = new Handler(){
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    Log.v(TAG,"handleMessage is running:"+msg.what);
                }
            };
            new Thread(){
                @Override
                public void run() {
                    super.run();
                    Log.v(TAG, "new a Thread");                   
                    for(int i = ; i < ;i ++){
                        mHandler.sendEmptyMessage(i);
                    }
                }
            }.start();            
           

或者

Runnable mRunnable = new Thread(){
                @Override
                public void run() {
                    super.run();
                    Log.v(TAG, "new a Thread:");

                    for(int i = ; i < ;i ++){
                        mHandler.sendEmptyMessage(i);
                    }
                }
            };
            new Handler().post(mRunnable);
           

使用Handler 存在的問題

記憶體方面

Handler 被作為 Activity 引用,如果為非靜态内部類,則會引用外部類對象。當 Activity finish 時,Handler可能并未執行完,進而引起 Activity 的記憶體洩漏。故而在所有調用 Handler 的地方,都用靜态内部類。

異常方面

當 Activity finish 時,在 onDestroy 方法中釋放了一些資源。此時 Handler 執行到 handlerMessage 方法,但相關資源已經被釋放,進而引起空指針的異常。為解決這個問題,如果是使用 handlerMessage,則在方法中加try catch。如果是用 post 方法,則在Runnable方法中加try catch。

二. Looper,MessageQueue,Hanlder

MessageQueue: 消息隊列,把加入的Message消息互相連結起來組成一個單連結清單。

Handler:負責把Message消息加入MessageQueue隊列中

Looper:負責循環讀取MessageQueue消息隊列中的消息,并把消息派發給相應的類處理(Handler,Runnable )

Hanlder的使用及其Looper,MessageQueue原理

ActivityThread:

public static void main(String[] args) {
        ......
        Looper.prepareMainLooper();//為UI線程設定Looper

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        Looper.loop();//循環讀取MessageQueue隊列,取出Message做處理

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }
           

Looper

public final class Looper {
    //靜态
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    //建構Looper對象
    public static void prepare() {
        prepare(true);
    }
    //建構Looper對象,并把新建構的Looper對象儲存到sThreadLocal 中
    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }    
    //建構UI線程的Looper對象
    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }
    //循環讀取MessageQueue隊列,取出Message并回調msg.target.dispatchMessage(msg)。target就是Handler對象的引用
    public static void loop() {
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;

        // Make sure the identity of this thread is that of the local process,
        // and keep track of what that identity token actually is.
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();
        //死循環讀取MessageQueue并取出Message
        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }
            ......
            try {
                msg.target.dispatchMessage(msg);//回調Handler中的dispatchMessage()函數
                end = (slowDispatchThresholdMs == ) ?  : SystemClock.uptimeMillis();
            } finally {
                if (traceTag != ) {
                    Trace.traceEnd(traceTag);
                }
            }
            .......
        }
    }    
    //取出儲存在sThreadLocal中的Looper對象
    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }    
           

MessageQueue

public final class MessageQueue {
    ......
    //Message加入隊列的操作
    boolean enqueueMessage(Message msg, long when) {......}
    ......
}
           

Handler

public class Handler {

    //如果Message中的callback為空,調用handleCallback(),否則調用handleMessage()
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }
    //回調callback中的run()方法,一般都是Runnable中的run()
    private static void handleCallback(Message message) {
        message.callback.run();
    }      
    //把Message消息加入到隊列中
    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);
    }    
    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }      
           

關于Looper:

每個線程都綁定一個唯一Looper,不能建構多個。如果新建構的線程沒有綁定新的Looper,那這個線程不能使用Handler,否則會報java.lang.RuntimeException: Can’t create handler inside thread that has not called Looper.prepare()錯誤。我們需要調用prepare()建立Looper對象,并循環取出MessageQueue中的資料,Looper.java源碼中的案例如下:

* <pre>
  *  class LooperThread extends Thread {
  *      public Handler mHandler;
  *
  *      public void run() {
  *          Looper.prepare();
  *
  *          mHandler = new Handler() {
  *              public void handleMessage(Message msg) {
  *                  // process incoming messages here
  *              }
  *          };
  *
  *          Looper.loop();
  *      }
  *  }</pre>
           

繼續閱讀