1. 程式人生 > >Android Hanlder機制分析(一) Hanlder常見用方法及原理

Android Hanlder機制分析(一) Hanlder常見用方法及原理

一、Handler介紹

  在android開發的過程中,經常需要對UI進行更新操作。但是在子執行緒中對UI進行更新在android中是不允許的,這涉及到了執行緒安全問題,因此更新UI只能在主執行緒(UI執行緒)中進行。但是如果將耗時操作放在了UI執行緒中會帶來程式體驗上卡頓甚至ANR等問題。然而通過Android的Handler機制能夠很好解決此類問題。
  Handler為UI的非同步跟新提供了一個很好的方式。Handler的主要作用是在子執行緒中進行耗時操作,將得到的資料通過handler 傳送個主執行緒(UI執行緒)主執行緒根據結果進行UI的更新。

二、Handler相關方法介紹

  在使用Handler的時,通常需要將Handler訊息傳送給主執行緒,常用的方法如下:
  sendEmptyMessage(int what):傳送空訊息
   boolean sendEmptyMessageDelayed(int what,long delayMillis):指定多少毫秒之後傳送空訊息
  sendMessage(Message msg):立即傳送訊息
  sendMessageDelayed(Message msg,long delayMillis):指定多少毫秒之後傳送訊息
  obtainMessage():從訊息佇列中返回一個Message
  sendMessageAtFrontOfQueue(Message msg):將message插入到messageQueue前列。
方法還有很多,此處不一一列舉。

三、Hanlder使用例項

  在使用Hanlder的時候通常需要以下幾個步驟;

private Handler mHandler;
        mHandler = new Handler() {
            @SuppressWarnings("unchecked")
            public void handleMessage(Message msg) {
                switch(msg.what) {
                case XX:
                需要執行的程式碼
                    break
; case XX: 需要執行的程式碼 break; default: break; } } };
 Message msg = new Message(); 
 msg.what = XXX;
mhandler.sendMessage();

總的說來分為了三步,先新建一個Handler的例項,再根據需求重寫了handleMessage(Message msg)方法,最後通過mHandler傳送訊息交由handleMessage(Message msg)處理。

四 Handler實現原理

Handler的實現與三個元件相關:
1.Message:Handler接收和處理的訊息物件
2.Looper:每個執行緒只能擁有一個Looper.它的loop方法負責讀取MessageQueue中的訊息,
讀到資訊之後就把訊息交給傳送該訊息的Handler進行處理。
3.MessageQueue:訊息佇列,它採用先進先出的方式來管理Message.
  在一個activity中,程式自動的幫我們綁定了一個loop到主執行緒。在ActivityThread.java可以看到:

public static void main(String[] args) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
        SamplingProfilerIntegration.start();

           ......

        // Make sure TrustedCertificateStore looks in the right place for CA certificates

        Looper.prepareMainLooper();

        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();
                .......
    }

因此,我們可以在UI執行緒中直接使用Handler。如果需要在自己執行緒中使用handler 則需要自己向執行緒繫結looper,具體實現在後面文章中詳細解釋。
現在我們來先看看 Looper,Message ,Handler他們之間的關係。
Message:訊息的載體。可以攜帶訊息種類、資料等資訊。
(1)public int what:變數,用於定義此Message屬於何種操作
(2)public Object obj:變數,用於定義此Message傳遞的資訊資料,通過它傳遞資訊
(3)public int arg1:變數,傳遞一些整型資料時使用
(4)public int arg2:變數,傳遞一些整型資料時使用
Looper:每一個執行緒只能有一個Looper,它負責這從MessageQueue中取出Message並將其分發給Handler處理。下面來看看Looper是怎麼執行的。

public final class Looper {

    private static final String TAG = "Looper";
......
    final MessageQueue mQueue;
    final Thread mThread;
    private Printer mLogging;

    public static void prepare() {
        prepare(true);
    }

    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));//
    }

    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;
        ......
/*迴圈裡,不斷從MessageQueue中取出msg ,根據msg所攜帶的資訊進行分發*/
        for (;;) {
            Message msg = queue.next(); // 取出msg
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            // This must be in a local variable, in case a UI event sets the logger
            Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }

            msg.target.dispatchMessage(msg);//分發訊息給handler 處理

           ......
    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

Handler 類主要用於處理自己發出的msg,而msg又在loop中進行取出。Handler原始碼如下:

 public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }

        mLooper = Looper.myLooper();//handler與looper繫結
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;//handler與msgqueue繫結
        mCallback = callback;
        mAsynchronous = async;
    }

綜上,在一個執行緒中綁定了一個looper後即成為了Looper執行緒。這looper執行緒中,可以新建Handler ,再通過handler例項向messageQueue中放入訊息,放入的訊息由looper取出再分發給相應的Handler處理。
(下一篇將寫怎麼去自建一個looperThread ,HanderThread ,以及hander.obtain()的優點)。