深入解析Android中Handler消息机制

2022-06-22 10:45:29 浏览数 (1)

Android提供了Handler 和 Looper 来满足线程间的通信。Handler先进先出原则。Looper类用来管理特定线程内对象之间的消息交换(MessageExchange)。Handler消息机制可以说是Android系统中最重要部分之一,所以,本篇博客我们就来深入解析Android中Handler消息机制。

Handler的简单使用

为什么系统不允许子线程更新UI

因为的UI控件不是线程安全的。 如果在多线程中并发访问可能会导致UI控件处于不可预期的状态,那为什么不对UI控件的访问加上上锁机制呢?因为有这么两个缺点: 1.上锁会让UI控件变得复杂和低效 2.上锁后会阻塞某些进程的执行 对于手机系统来说,这两个缺点是不可接受的,所以最简单高效的方法就是 —— 采用单线程模型来处理UI操作。 对开发者而言也不是很麻烦,只是通过Handler切换一下访问的线程的就好。

Handler的简单使用

既然子线程不能更改界面,那么我们现在就借助Handler让我们更改一下界面: 主要步骤是这样子的: 1.new出来一个Handler对象,复写handleMessage方法 2.在需要执行更新UI的地方 sendEmptyMessage 或者 sendMessage 3.在handleMessage里面的switch里面case不同的常量执行相关操作

代码语言:javascript复制
public class MainActivity extends ActionBarActivity {

    private TextView mTextView;
    private Handler mHandler;
    private static final int UI_UPDATE1 = 0;
    private static final int UI_UPDATE2 = 1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mHandler = new Handler() {

            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                case UI_UPDATE1:
                    mTextView.setText("通过Handler方法1修改UI");
                    break;
                case UI_UPDATE2:
                    mTextView.setText("通过Handler方法2修改UI");
                    break;
                }
            }

        };
        mTextView = (TextView) findViewById(R.id.textview);
        mTextView.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                Log.d("Test", "点击文字");
                updateUi();
            }
        });
    }

    protected void updateUi() {
        new Thread(new Runnable() {

            @Override
            public void run() {
                // 方式一和方式二可以达到相同的效果,就是更改界面
                //方式一
                //mHandler.sendEmptyMessage(UI_UPDATE1);
                //方式二
                Message msg = Message.obtain();
                msg.what = UI_UPDATE2;
                mHandler.sendMessage(msg);

            }
        }).start();

    }
}
代码语言:javascript复制
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.handlerdemo3.MainActivity" >

    <TextView
        android:id="@ id/textview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world"
        android:layout_centerInParent="true"
        android:clickable="true" />

</RelativeLayout>

消息机制的分析理解

安卓的异步消息处理机制就是handler机制。 主线程,ActivityThread被创建的时候就会创建Looper Looper被创建的时候创建MessageQueue。 也就是说主线程会直接或间接创建出来Looper和MessageQueue。 Handler的工作机制简单来说是这样的 1.Handler发送消息仅仅是调用MessageQueue的enqueueMessage向插入一条信息到MessageQueue 2.Looper不断轮询调用MeaasgaQueue的next方法 3.如果发现message就调用handler的dispatchMessage,dispatchMessage被成功调用,接着调用handlerMessage()

Handler消息机制的源码分析

ThreadLocal工作原理 首先,ThreadLocal 不是用来解决共享对象的多线程访问问题的,一般情况下,通过ThreadLocal.set() 到线程中的对象是该线程自己使用的对象,其他线程是不需要访问的,也访问不到的。各个线程中访问的是不同的对象。

另外,说ThreadLocal使得各线程能够保持各自独立的一个对象,并不是通过ThreadLocal.set()来实现的,而是通过每个线程中的new 对象 的操作来创建的对象,每个线程创建一个,不是什么对象的拷贝或副本。通过ThreadLocal.set()将这个新创建的对象的引用保存到各线程的自己的一个map中,每个线程都有这样一个map,执行ThreadLocal.get()时,各线程从自己的map中取出放进去的对象,因此取出来的是各自自己线程中的对象,ThreadLocal实例是作为map的key来使用的。

如果ThreadLocal.set()进去的东西本来就是多个线程共享的同一个对象,那么多个线程的ThreadLocal.get()取得的还是这个共享对象本身,还是有并发访问问题。

我们看一下ThreadLocal的set方法

代码语言:javascript复制
public void set(T value) {
        Thread currentThread = Thread.currentThread();
        Values values = values(currentThread);
        if (values == null) {
            values = initializeValues(currentThread);
        }
        values.put(this, value);
}

查看values方法里面做了什么

代码语言:javascript复制
Values values(Thread current) {
        return current.localValues;
}

通过上面代码我们可以知道,当values为空的时候,才调用initializeValues方法进行初始化,查看inheritValues相关逻辑:

代码语言:javascript复制
private void inheritValues(Values fromParent) {
            // Transfer values from parent to child thread.
            Object[] table = this.table;
            for (int i = table.length - 2; i >= 0; i -= 2) {
                Object k = table[i];

                if (k == null || k == TOMBSTONE) {
                    // Skip this entry.
                    continue;
                }

                // The table can only contain null, tombstones and references.
                Reference<InheritableThreadLocal<?>> reference
                        = (Reference<InheritableThreadLocal<?>>) k;
                // Raw type enables us to pass in an Object below.
                InheritableThreadLocal key = reference.get();
                if (key != null) {
                    // Replace value with filtered value.
                    // We should just let exceptions bubble out and tank
                    // the thread creation
                    table[i   1] = key.childValue(fromParent.table[i   1]);
                } else {
                    // The key was reclaimed.
                    table[i] = TOMBSTONE;
                    table[i   1] = null;
                    fromParent.table[i] = TOMBSTONE;
                    fromParent.table[i   1] = null;

                    tombstones  ;
                    fromParent.tombstones  ;

                    size--;
                    fromParent.size--;
                }
            }
        }

其实就是各种赋值table数组,进行初始化 最后才是调用values.put(this, value)把ThreadLocal和value一起保存,我们可以看一下values.put(this, value)方法

代码语言:javascript复制
void put(ThreadLocal<?> key, Object value) {
            cleanUp();

            // Keep track of first tombstone. That's where we want to go back
            // and add an entry if necessary.
            int firstTombstone = -1;

            for (int index = key.hash & mask;; index = next(index)) {
                Object k = table[index];

                if (k == key.reference) {
                    // Replace existing entry.
                    table[index   1] = value;
                    return;
                }

                if (k == null) {
                    if (firstTombstone == -1) {
                        // Fill in null slot.
                        table[index] = key.reference;
                        table[index   1] = value;
                        size  ;
                        return;
                    }

                    // Go back and replace first tombstone.
                    table[firstTombstone] = key.reference;
                    table[firstTombstone   1] = value;
                    tombstones--;
                    size  ;
                    return;
                }

                // Remember first tombstone.
                if (firstTombstone == -1 && k == TOMBSTONE) {
                    firstTombstone = index;
                }
            }
        }

可以看出,Threadlocal的值在table数组的存储位置总是reference的下一个位置.

接下来,查看Threadlocal的get方法

Get方法的逻辑是:通过values方法取出当前线程的localValues对象,如果为null,就返回初始值。如果localValues不为null,取出其table数组,如果reference等于table数组index角标的值,就在table[index 1]取出其Threadlocal值。

MessageQueue工作原理

MessageQueue中文翻译就是消息队列,它内部存储了一组信息,存放的是Message,以队列的形式对外提供了插入和删除的工作(虽然名字叫做队列,但是其内部的 存储结构是单链表) 主要 插入 和 读取 两个操作,这两个操作对应着两个方法:

代码语言:javascript复制
插入(入队) enqueueMessage(Message msg, long when)
读取(出队) next()

查看enqueueMessage的源码:

代码语言:javascript复制
boolean enqueueMessage(Message msg, long when) {
        if (msg.isInUse()) {
            throw new AndroidRuntimeException(msg   " This message is already in use.");
        }
        if (msg.target == null) {
            throw new AndroidRuntimeException("Message must have a target.");
        }

        boolean needWake;
        synchronized (this) {
            if (mQuiting) {
                RuntimeException e = new RuntimeException(
                        msg.target   " sending message to a Handler on a dead thread");
                Log.w("MessageQueue", e.getMessage(), e);
                return false;
            }

            msg.when = when;
            Message p = mMessages;
            if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked.
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
                // Inserted within the middle of the queue.  Usually we don't have to wake
                // up the event queue unless there is a barrier at the head of the queue
                // and the message is the earliest asynchronous message in the queue.
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
                for (;;) {
                    prev = p;
                    p = p.next;
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                msg.next = p; // invariant: p == prev.next
                prev.next = msg;
            }
        }
        if (needWake) {
            nativeWake(mPtr);
        }
        return true;

从enqueueMessage的实现来看,主要操作就是单链表的插入操作,接下来查看next方法的实现:

代码语言:javascript复制
Message next() {
        // Return here if the message loop has already quit and been disposed.
        // This can happen if the application tries to restart a looper after quit
        // which is not supported.
        final long ptr = mPtr;
        if (ptr == 0) {
            return null;
        }

        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        int nextPollTimeoutMillis = 0;
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }

            nativePollOnce(ptr, nextPollTimeoutMillis);

            synchronized (this) {
                // Try to retrieve the next message.  Return if found.
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;
                if (msg != null && msg.target == null) {
                    // Stalled by a barrier.  Find the next asynchronous message in the queue.
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                }
                if (msg != null) {
                    if (now < msg.when) {
                        // Next message is not ready.  Set a timeout to wake up when it is ready.
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        // Got a message.
                        mBlocked = false;
                        if (prevMsg != null) {
                            prevMsg.next = msg.next;
                        } else {
                            mMessages = msg.next;
                        }
                        msg.next = null;
                        if (DEBUG) Log.v(TAG, "Returning message: "   msg);
                        msg.markInUse();
                        return msg;
                    }
                } else {
                    // No more messages.
                    nextPollTimeoutMillis = -1;
                }

                // Process the quit message now that all pending messages have been handled.
                if (mQuitting) {
                    dispose();
                    return null;
                }

                // If first time idle, then get the number of idlers to run.
                // Idle handles only run if the queue is empty or if the first message
                // in the queue (possibly a barrier) is due to be handled in the future.
                if (pendingIdleHandlerCount < 0
                        && (mMessages == null || now < mMessages.when)) {
                    pendingIdleHandlerCount = mIdleHandlers.size();
                }
                if (pendingIdleHandlerCount <= 0) {
                    // No idle handlers to run.  Loop and wait some more.
                    mBlocked = true;
                    continue;
                }

                if (mPendingIdleHandlers == null) {
                    mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
                }
                mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
            }

            // Run the idle handlers.
            // We only ever reach this code block during the first iteration.
            for (int i = 0; i < pendingIdleHandlerCount; i  ) {
                final IdleHandler idler = mPendingIdleHandlers[i];
                mPendingIdleHandlers[i] = null; // release the reference to the handler

                boolean keep = false;
                try {
                    keep = idler.queueIdle();
                } catch (Throwable t) {
                    Log.wtf(TAG, "IdleHandler threw exception", t);
                }

                if (!keep) {
                    synchronized (this) {
                        mIdleHandlers.remove(idler);
                    }
                }
            }

            // Reset the idle handler count to 0 so we do not run them again.
            pendingIdleHandlerCount = 0;

            // While calling an idle handler, a new message could have been delivered
            // so go back and look again for a pending message without waiting.
            nextPollTimeoutMillis = 0;
        }
    }

从上面代码可以得出以下结论: 1.next方法是一个无限循环的方法,如果消息队列中没有消息,那么next方法会一直阻塞 2.当有新消息到来,next方法会返回这条消息,并将其从单链表中移除。

Looper的工作原理

Looper是一个轮询器,它的作用不断轮询MessageQueue,当如果有新的消息就交给Handler处理,如果轮询不到新的消息,那就自身就处于阻塞状态。

查看Looper类的源码,可以发现的他的构造方法里面创建了一个MessageQueue,然后将当前线程的对象保存起来

代码语言:javascript复制
private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

在Looper的构造方法中初始化了一个消息队列MessageQueue和一个线程Thread。从这可看出:一个Looper对应着一个消息队列以及当前线程。 当收到消息Message后系统会将其存入消息队列中等候处理。至于Looper,它在Android的消息机制中担负着消息轮询的职责,它会不间断地查看MessageQueue中是否有新的未处理的消息;若有则立刻处理,若无则进入阻塞。

相信大家一定有遇到过,在子线程中创建Handler会报如下错误

解决办法就是new Handler的时候加上Looper.prepare(); 而Looper.prepare()的内部实现逻辑就是创建一个Looper

代码语言:javascript复制
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));
    }

线程默认是没有Looper的,但是为什么在主线程没有创建的Looper就可以使用Handler?主线程是特别的。主线程,也就是ActivityThread,当主线程被创建的时候,会调用Looper内的prepareMainLooper方法,创建Looper,该方法是专门给主线程创建Looper用的。也正因为这点,所以我们在主线程创建了Handler就直接能用了。

代码语言:javascript复制
 public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

由于这个特殊性,Looper还提供了一个getMainLooper方法,使得可以在任何地方获取主线程的Looper。

代码语言:javascript复制
public static Looper getMainLooper() {
        synchronized (Looper.class) {
            return sMainLooper;
        }
    }

接下来,我们看一下Looper的退出

Looper提供了两个方法进行退出操作,分别是quit和quitSafely,他们调用的是MessageQueue的quit方法

代码语言:javascript复制
public void quit() {
        mQueue.quit(false);
    }
代码语言:javascript复制
public void quitSafely() {
        mQueue.quit(true);
    }

MessageQueue的quit方法:

代码语言:javascript复制
 void quit(boolean safe) {
        if (!mQuitAllowed) {
            throw new IllegalStateException("Main thread not allowed to quit.");
        }

        synchronized (this) {
            if (mQuitting) {
                return;
            }
            mQuitting = true;

            if (safe) {
                removeAllFutureMessagesLocked();
            } else {
                removeAllMessagesLocked();
            }

            // We can assume mPtr != 0 because mQuitting was previously false.
            nativeWake(mPtr);
        }
    }

如果调用Looper.quit方法,最终会调用removeAllMessagesLocked方法,该方法逻辑:直接遍历所有的消息,并将消息强制回收

代码语言:javascript复制
   private void removeAllMessagesLocked() {
        Message p = mMessages;
        while (p != null) {
            Message n = p.next;
            p.recycleUnchecked();
            p = n;
        }
        mMessages = null;
    }

如果调用Looper.quitSafely方法,最终会调removeAllFutureMessagesLocked方法,该方法逻辑:

代码语言:javascript复制
void removeCallbacksAndMessages(Handler h, Object object) {
        if (h == null) {
            return;
        }

        synchronized (this) {
            Message p = mMessages;

            // Remove all messages at front.
            while (p != null && p.target == h
                    && (object == null || p.obj == object)) {
                Message n = p.next;
                mMessages = n;
                p.recycleUnchecked();
                p = n;
            }

            // Remove all messages after front.
            while (p != null) {
                Message n = p.next;
                if (n != null) {
                    if (n.target == h && (object == null || n.obj == object)) {
                        Message nn = n.next;
                        n.recycleUnchecked();
                        p.next = nn;
                        continue;
                    }
                }
                p = n;
            }
        }
    }

一个无限for循环,只有n.when > now和n == null才会跳出循环,说明是等消息队列中已有的消息处理完毕后,才会跳出,然后执行回收。

Looper这个类里面最重要的方法就是loop()开启消息循环这个方法了,看一下loop代码的实现逻辑:

代码语言:javascript复制
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();

        for (;;) {
            Message msg = queue.next(); // might block
            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
            final Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to "   msg.target   " "  
                        msg.callback   ": "   msg.what);
            }

            final long traceTag = me.mTraceTag;
            if (traceTag != 0) {
                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
            }
            try {
                msg.target.dispatchMessage(msg);
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }

            if (logging != null) {
                logging.println("<<<<< Finished to "   msg.target   " "   msg.callback);
            }

            // Make sure that during the course of dispatching the
            // identity of the thread wasn't corrupted.
            final long newIdent = Binder.clearCallingIdentity();
            if (ident != newIdent) {
                Log.wtf(TAG, "Thread identity changed from 0x"
                          Long.toHexString(ident)   " to 0x"
                          Long.toHexString(newIdent)   " while dispatching to "
                          msg.target.getClass().getName()   " "
                          msg.callback   " what="   msg.what);
            }

            msg.recycleUnchecked();
        }
    }

通过代码我们知道:looper方法是一个死循环,唯一跳出的循环的方式是MessageQueue的next方法返回null,但这几乎不可能,因为在MessageQueue的next方法中,假如没有消息加入队列,next方法会一直阻塞,不会返回null。如果我们不手动调用quit或者quitSafely方法的话,MessageQueue的next方法是不可能返回null的。 当MessageQueue没有消息时,next方法会一直阻塞在那里,因为MessageQueue的next方法阻塞了,就导致Looper的loop方法也一直在阻塞了。 这里我们那一分为二的谈, loop轮询不到消息:那么处于阻塞状态,然后就没有然后了,除了又轮询到了新的消息 loop轮到了新的消息:Looper就会处理消息 1、msg.target.dispatchMessage(msg),这里的 msg.target就是指Handler对象 2、到了最后,Handler发送的消息又交给了自己的dispatchMessage方法来处理了。(这个dispatchMessage方法不是Handler自己调用时,是与Handler相相关的Looper间接调用的),这样下来,就成功地将逻辑切换到指定的线程当中去了

Handler的工作原理 Handler的主要工作:消息的 发送 和 接收 。Handler消息发送的形式有post和send两种。 查看Handler中sendMessage代码

代码语言:javascript复制
public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
    }

sendMessage调用sendMessageDelayed

代码语言:javascript复制
public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis()   delayMillis);
    }

sendMessageDelayed调用sendMessageAtTime

代码语言:javascript复制
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);
    }

sendMessageAtTime调用enqueueMessage

代码语言:javascript复制
  private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }
代码语言:javascript复制
boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
        if (msg.isInUse()) {
            throw new IllegalStateException(msg   " This message is already in use.");
        }

        synchronized (this) {
            if (mQuitting) {
                IllegalStateException e = new IllegalStateException(
                        msg.target   " sending message to a Handler on a dead thread");
                Log.w(TAG, e.getMessage(), e);
                msg.recycle();
                return false;
            }

            msg.markInUse();
            msg.when = when;
            Message p = mMessages;
            boolean needWake;
            if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked.
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
                // Inserted within the middle of the queue.  Usually we don't have to wake
                // up the event queue unless there is a barrier at the head of the queue
                // and the message is the earliest asynchronous message in the queue.
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
                for (;;) {
                    prev = p;
                    p = p.next;
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                msg.next = p; // invariant: p == prev.next
                prev.next = msg;
            }

            // We can assume mPtr != 0 because mQuitting is false.
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }

得出结论:Handler的发送消息仅仅是调用MessageQueue的enqueueMessage向插入一条信息到MessageQueue,MessageQueue就会返回这条消息给Looper,Looper会交给msg.target.dispatchMessage(msg)方法处理,就进入消息处理阶段。

查看dispatchMessage方法

代码语言:javascript复制
/**
     * Handle system messages here.
     */
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

首先,判断 Message. Callback是否为null,不为null,就调用handleCallback方法

代码语言:javascript复制
private static void handleCallback(Message message) {
        message.callback.run();
    }

Callback是一个Runnable对象,实际上就是post方法传递的Runnable参数。 其次,检查mCallback是否为null,如果不为null就调用mCallback.handleMessage方法,查看mCallback.handleMessage方法

代码语言:javascript复制
 public interface Callback {
        public boolean handleMessage(Message msg);
    }

源码中注释已经对Callback进行了解释: 可以用来创建一个Handler的实例但不需要派生Handler的子类 在日常开发中,创建Handler最常见的方式就是派生一个Handler的子类并重写handleMessage方法来处理具体的消息,而Callback给我们提供了另外一种方式,不需要派生Handler的子类。

最后,调用Handler的handleMessage方法,这就是我们平时写Handler要实现的方法

主线程的消息循环 Android的主线程就是ActivityThread,主线程的路口方法是main方法,在 main中系统会通过Looper.prepareMainLooper()来创建主线程的Looper以及MessageQueue, 并通过Looper.loop()开启主线程消息循环

代码语言:javascript复制
public static void main(String[] args) {
        SamplingProfilerIntegration.start();

        // CloseGuard defaults to true and can be quite spammy.  We
        // disable it here, but selectively enable it later (via
        // StrictMode) on debug builds, but using DropBox, not logs.
        CloseGuard.setEnabled(false);

        Environment.initForCurrentUser();

        // Set the reporter for event logging in libcore
        EventLogger.setReporter(new EventLoggingReporter());

        Security.addProvider(new AndroidKeyStoreProvider());

        Process.setArgV0("<pre-initialized>");

        Looper.prepareMainLooper();

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

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

        AsyncTask.init();

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

        Looper.loop();

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

主线程开始循环后,ActivityThread还需要一个Handler来和消息队列进行交互,这个Handler就是ActivityThread.H

ApplicationThread通过binder与Ams通信,并将Ams的调用,通过H类(也就是Hnalder)将消息发送到消息队列,然后进行相应的操作,H收到消息后,就会将ApplicationThread中逻辑切换到ActivityThread中执行,也就是主线程中执行,这个过程就是主线程的消息循环。

至此,Handler消息机制就分析完毕,如有错漏,欢迎留言指证。

0 人点赞