Android Handler/Looper/MessageQu

2018-11-16  本文已影响0人  CyanStone

Android的View模型采用的是单线程模型,所有的视图相关的操作都必须在主线程中进行,否则会抛出异常。某些耗时的操作需要放入工作线程中,执行完后通过异步消息处理机制把结果传入主线程中进行刷新UI等操作。异步消息处理机制主要由Handler\Looper\MessageQueue\Message几个类,它工作的原理网上有很多资料,这里不再赘述。接下来深入剖析下相关源码(源码基于android8.0)。

1. Message

Message顾名思义,是一个消息,是多线程间通信的实体,是Handler发送和处理的对象。Message对象实现了Parcelable接口,说明Message对象支持序列化/反序列化操作。

成员变量
//标识消息的code
public int what;
//存储int类型的数据域
public int arg1;
//存储int类型的数据域
public int arg2;
//存储对象的数据域
public Object obj;
//消息标识,当消息被回收放入到消息池时会被打上FLAG_IN_USE标识
/*package*/
int flags;
//记录消息的时间戳
/*package*/
long when;
//Bundle数据域
/*package*/
Bundle data;
//发送和处理消息的Handler
/*package*/
Handler target;
//回调接口,消息可以被Handler处理,也可以被自身的Runnable对象处理
/*package*/
Runnable callback;

// 链式结构,指向下一个Massgage对象,用于维护链表结构的消息池
/*package*/
Message next;
//静态域,信号量,可理解成这个对象是为了同步加锁创建的,所有需要对消息池进行的操作,会对该对象进行加锁同步
private static final Object sPoolSync = new Object();
//静态域,链表结构消息池的表头,由它维护了一个链式空闲消息池,当消息被回收的时候,会加入到这个消息池中
private static Message sPool;
//静态域,消息池大小
private static int sPoolSize = 0;
//消息池最大容量是50
private static final int MAX_POOL_SIZE = 50;
//在回收消息之前是否需要检查消息是否是在被使用当中
private static boolean gCheckRecycle = true;

从Message定义的这些变量可知以下几点:

obtain()方法

通过Meaasge.obtain()可以获得一个Message对象:

public static Message obtain() {
    synchronized(sPoolSync) {
        if (sPool != null) {
            Message m = sPool;
            sPool = m.next;
            m.next = null;
            m.flags = 0; // clear in-use flag
            sPoolSize--;
            return m;
        }
    }
    return new Message();
}

获取一个Message对象的源码很简单,先加锁,如果消息池是空的,直接new一个新的Message对象出来,否则从链表头取出一个Message对象,把它暂时从消息池中删除,并清除它的flag。需要注意的是,obtain静态方法有很多重载的实现,但都是先调用Meaasge.obtain()方法获取到一个Message对象,再对相关变量进行赋值。

recycle()方法

在一个Message被使用完以后,调用recycle()方法会被回收:

public void recycle() {
    if (isInUse()) {
        if (gCheckRecycle) {
            throw new IllegalStateException("This message cannot be recycled because it " + "is still in use.");
        }
        return;
    }
    recycleUnchecked();
}

/**
     * Recycles a Message that may be in-use.
     * Used internally by the MessageQueue and Looper when disposing of queued Messages.
     */
void recycleUnchecked() {
    // Mark the message as in use while it remains in the recycled object pool.
    // Clear out all other details.
    flags = FLAG_IN_USE;
    what = 0;
    arg1 = 0;
    arg2 = 0;
    obj = null;
    replyTo = null;
    sendingUid = -1;
    when = 0;
    target = null;
    callback = null;
    data = null;

    synchronized(sPoolSync) {
        if (sPoolSize < MAX_POOL_SIZE) {
            next = sPool;
            sPool = this;
            sPoolSize++;
        }
    }
}

recycle()方法其实调用的是recycleUnchecked()方法,在这个方法中,会将flag标记为FLAG_IN_USE,并把所有的域清空,并在消息池没有达到最大限定值的情况下,把这个对象插入消息池的表头。同样,在操作消息池的时候需要先对sPoolSync信号量加锁。
Message除了上述关键的方法以外,还有一些setter/getter、toString()方法、设置消息flag、判断消息flag和实现Parceable接口的方法,具体不再分析,感兴趣的同学可以自行去查看。


2.MessageQueue

MessageQueue是消息处理队列,在异步消息处理中,需要调用enqueueMessage()方法将消息入队到MessageQueue中,然后通过next()方法取出,交给Handler去处理消息。MessageQueue的类由final修饰,禁止对其进行继承、修改。

成员变量

下面来看MessageQueue中定义的成员变量变量:

// True if the message queue can be quit.
private final boolean mQuitAllowed;

@SuppressWarnings("unused") private long mPtr; // used by native code
Message mMessages;
private final ArrayList < IdleHandler > mIdleHandlers = new ArrayList < IdleHandler > ();
private SparseArray < FileDescriptorRecord > mFileDescriptorRecords;
private IdleHandler[] mPendingIdleHandlers;
private boolean mQuitting;
// Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout.
private boolean mBlocked;

// The next barrier token.
// Barriers are indicated by messages with a null target whose arg1 field carries the token.
private int mNextBarrierToken;
IdleHandler
public static interface IdleHandler {
    boolean queueIdle();
}

public void addIdleHandler(@NonNull IdleHandler handler) {
    if (handler == null) {
        throw new NullPointerException("Can't add a null IdleHandler");
    }
    synchronized(this) {
        mIdleHandlers.add(handler);
    }
}

public void removeIdleHandler(@NonNull IdleHandler handler) {
    synchronized(this) {
        mIdleHandlers.remove(handler);
    }
}
  

从上述部分源码知道,IdleHandler是一个接口,可以通过addIdleHandler和removeHandler往mIdleHandlers中添加和移除IdleHandler的实现类的实例。

构造方法
MessageQueue(boolean quitAllowed) {
    mQuitAllowed = quitAllowed;
    mPtr = nativeInit();
}

MessageQueue的构造函数需要传入quitAllowed参数,代表是否允许MessageQueue退出。

next()方法
//取出下一个入队的消息
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;
    }
    //需要处理的IdleHandler的数量
    int pendingIdleHandlerCount = -1; // -1 only during first iteration
    int nextPollTimeoutMillis = 0;
    //死循环去拿Message,直到返回一个Message,或者MessageQueue退出
    for (;;) {
        if (nextPollTimeoutMillis != 0) {
            Binder.flushPendingCommands();
        }

        nativePollOnce(ptr, nextPollTimeoutMillis);

        synchronized(this) {
            // Try to retrieve the next message.  Return if found.
            //去拿一个消息,拿到后return
            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            //拿到队头,如果拿到的是一个屏障
            //(或者叫拦截器,target一定为null,arg1里保存着屏障的token),
            //则往后遍历队列,直到拿到一个异步消息
            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.
                    //如果拿到的消息的执行时间未到,更新nextPollTimeoutMills
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                } else {
                    // Got a message.
                    mBlocked = false;
                    if (prevMsg != null) {
                        //preMsg不为空,说明此时队列头是一个barrier,msg此时是异步消息。
                        //preMsg是msg的前驱节点,把msg从队列中删除
                        prevMsg.next = msg.next;
                    } else {
                        //此时Msg依旧为队头,所以只需要将头结点删掉即可
                        mMessages = msg.next;
                    }
                    //将取出的消息的next域置为null
                    msg.next = null;
                    if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                    //把消息msg打上FLAG_IN_USE操作,使用的是位或运算
                    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.
            //如果队列为空或者队头的消息没有到执行时间(在未来执行),
            //则执行idleHandlers的queueIdle()
            if (pendingIdleHandlerCount < 0 && (mMessages == null || now < mMessages.when)) {
                pendingIdleHandlerCount = mIdleHandlers.size();
            }
            if (pendingIdleHandlerCount <= 0) {
                // No idle handlers to run.  Loop and wait some more.
                //没有IdleHandlers需要被执行,则继续for循环,直到拿到消息
                mBlocked = true;
                continue;
            }

            if (mPendingIdleHandlers == null) {
                mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
            }
            //把mIdleHanders的内容复制到mPendingIdleHandlers的数组中,等待被执行
            mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
        }

        // Run the idle handlers.
        // We only ever reach this code block during the first iteration.
        //遍历pendingIdleHandler数组,依次执行IdleHandler.queueIdle()方法
        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 {
                //执行queueIdle()
                keep = idler.queueIdle();
            } catch(Throwable t) {
                Log.wtf(TAG, "IdleHandler threw exception", t);
            }

            //如果queueIdle()的执行结果为false,
            //则把对应的IdleHandler从mIdleHandlers中移除,
            //否则,下次队列空闲的时候,还会把mIdleHandlers的
            //内容复制到mPendingIdleHandlers中再次执行;
            if (!keep) {
                synchronized(this) {
                    mIdleHandlers.remove(idler);
                }
            }
        }

        // Reset the idle handler count to 0 so we do not run them again.
        //执行完以后把变量置0
        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;
    }
}

针对next()方法需要说明以下几点:

enqueueMessage()方法
boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {
           //入队的消息的target,必须不为空,否则会抛异常
            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) {
                 //如果消息队列在退出状态 ,则直接回收消息,返回false
                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;
            }
           //把消息标记为在使用状态,设置when
            msg.markInUse();
            msg.when = when;
           //此时p指向链表头
            Message p = mMessages;
            boolean needWake;
            if (p == null || when == 0 || when < p.when) {
                //如果队列为空或者when等于0,或者when小于
                //队头Message的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的前驱节点,依次遍历
                    prev = p;
                    p = p.next;
                    //当p已经到队尾或者找到一个节点msg.when < p.when时退出循环
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
               //链表插入操作,把msg插入到p节点前边,并把p的前驱节点的next改为msg
                msg.next = p; // invariant: p == prev.next
                prev.next = msg;
            }

            // We can assume mPtr != 0 because mQuitting is false.
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        //插入成功,返回true
        return true;
    }

针对消息入队函数enqueueMessage()方法,需要说明以下几点:

quit()方法
void quit(boolean safe) {
    if (!mQuitAllowed) {
        //如果不允许退出,调用该方法,会抛出异常
        throw new IllegalStateException("Main thread not allowed to quit.");
    }
    //对自身进行加锁同步
    synchronized(this) {
        //如果已经是退出状态了,再次退出,直接返回
        if (mQuitting) {
            return;
        }
        //把mQuitting置为true,标识队列已经退出。一旦队列
        //是退出状态,则无法再次使用,除非再次new一个MessageQueue
        mQuitting = true;
        //参数safe标识是否为安全退出,ture会将还未到执行时间的Message
        //(在未来时刻执行)remove掉并清除Message的内容;false会移除
        //全部Message并清除Message的内容
        if (safe) {
            removeAllFutureMessagesLocked();
        } else {
            removeAllMessagesLocked();
        }

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

private void removeAllFutureMessagesLocked() {
    final long now = SystemClock.uptimeMillis();
    Message p = mMessages;
    if (p != null) {
        //如果队头的执行时间已经是在未来时刻了,则直接调用
        //removeAllMessagesLocked()方法清除所有的消息
        if (p.when > now) {
            removeAllMessagesLocked();
        } else {
            Message n;
            //for循环找出Message的执行时间大于now的节点,
            //退出循环
            for (;;) {
                n = p.next;
                if (n == null) {
                    return;
                }
                if (n.when > now) {
                    break;
                }
                p = n;
            }
            p.next = null;
            //while循环遍历,调用Message.recycleUncheked()方法
            //清除消息内容,并从队列中删除
            do {
                p = n;
                n = p.next;
                p.recycleUnchecked();
            } while ( n != null );
        }
    }
}
//循环遍历,清除消息队列中所有Message的内容并从队列中删除
private void removeAllMessagesLocked() {
    Message p = mMessages;
    while (p != null) {
        Message n = p.next;
        p.recycleUnchecked();
        p = n;
    }
    mMessages = null;
}

MessageQueue里还有判断队列中是否有特定消息和移除特定消息的一系列重载方法、一些native方法等,有兴趣的同学可以去看下,这里不再分析。


3.Handler

Handler是消息分发对象,可以发送Message和处理Message。

成员变量
//j是否发现潜在的内存泄漏,默认为false
private static final boolean FIND_POTENTIAL_LEAKS = false;
private static final String TAG = "Handler";
//静态全局变量,主线程的Handler
private static Handler MAIN_THREAD_HANDLER = null;

//绑定的Looper对象
final Looper mLooper;
//绑定的MessageQueue消息队列
final MessageQueue mQueue;
//回调接口的实现
final Callback mCallback;
//是否是异步的,如果是异步的,在发送消息的时候,
//会调用Message.setAsynchronous(true)把消息设为异步消息
final boolean mAsynchronous;
IMessenger mMessenger;
Callback、dispatchMessage()方法
public interface Callback {
    /**
         * @param msg A {@link android.os.Message Message} object
         * @return True if no further handling is desired
         */
    public boolean handleMessage(Message msg);
}

/**
     * Subclasses must implement this to receive messages.
     */
public void handleMessage(Message msg) {}

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

private static void handleCallback(Message message) {
    message.callback.run();
}
构造函数
public Handler() {
    this(null, false);
}

public Handler(Callback callback) {
    this(callback, false);
}

public Handler(Looper looper) {
    this(looper, null, false);
}

public Handler(Looper looper, Callback callback) {
    this(looper, callback, false);
}

public Handler(boolean async) {
    this(null, async);
}

public Handler(Callback callback, boolean async) {
    if (FIND_POTENTIAL_LEAKS) {
        //如果FIND_POTENTIAL_LEAKS设为true,如果Handler自身对象是匿名类、内部成员
        //类和本地类而且不是static的时候,会给出警告,可能有潜在的内存泄漏风险
        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());
        }
    }
    //调用Looper.myLooper()方法获得一个Looper对象,源码下文分析
    mLooper = Looper.myLooper();
    if (mLooper == null) {
        throw new RuntimeException("Can't create handler inside thread that has not called Looper.prepare()");
    }
    //MessageQueue直接拿Looper对象里的mQueue对象
    mQueue = mLooper.mQueue;
    mCallback = callback;
    //设置是否异步
    mAsynchronous = async;
}

public Handler(Looper looper, Callback callback, boolean async) {
    mLooper = looper;
    mQueue = looper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}
obtainMessage()方法
public final Message obtainMessage() {
    return Message.obtain(this);
}
post(Runnable r)相关方法

在Handler中,可以发送一个Runnable对象,也可以发送一个Message对象,现在我们先来分析发送Runnable对象的相关方法:

//立即post一个Runnable到MessageQueue中,此时Runnable被包装正Message后放在MessageQueue队列中(when == 当前系统时间,可能是队头,也可能不是队头,队列中已经有when值小于当前时间的Message)
public final boolean post(Runnable r) {
    return sendMessageDelayed(getPostMessage(r), 0);
}
//Runnable包装成Message后加入到MessageQueue中,但此时
//Message.when=uptimeMillis,uptimeMills是消息的执行时间,
//即指定了具体的执行系统时间
public final boolean postAtTime(Runnable r, long uptimeMillis) {
    return sendMessageAtTime(getPostMessage(r), uptimeMillis);
}
//同上,只是又传入了token对象,存储在Message.obj中
public final boolean postAtTime(Runnable r, Object token, long uptimeMillis) {
    return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
}
//Runnable包装成Message后加入到MessageQueue中,
//但是Message.when等于当前时间+delayMillis,
//表示延迟delayMills后执行
public final boolean postDelayed(Runnable r, long delayMillis) {
    return sendMessageDelayed(getPostMessage(r), delayMillis);
}
//Runnable包装成Message后加入到MessageQueue中,此时when=0,
//一定是在MessageQueue的队头
public final boolean postAtFrontOfQueue(Runnable r) {
    return sendMessageAtFrontOfQueue(getPostMessage(r));
}
//把Runnable对象包装成Message对象,可见只是把Runnable对象
//赋值给了Message的callback域
private static Message getPostMessage(Runnable r) {
    Message m = Message.obtain();
    m.callback = r;
    return m;
}
//上述方法的重载方法,把token赋值给了Message的obj域,
//可以用这个方法进行传值
private static Message getPostMessage(Runnable r, Object token) {
    Message m = Message.obtain();
    m.obj = token;
    m.callback = r;
    return m;
}
//延迟发送,把当前时间加上延迟时间后调用了sendMessageAtTime()方法
public final boolean sendMessageDelayed(Message msg, long delayMillis) {
    if (delayMillis < 0) {
        delayMillis = 0;
    }
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
//发送消息的方法,对queue判空后,调用enqueueMessage进行实际入队
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);
}
//实际对消息入队的方法,在该方法中,会把Message的target域进行赋值,
//如果mAsynchronous是true,则会调用setter方法把消息设置为异步消息,
//调用的入队方法其实是调用的MessageQueue的enqueueMessage方法
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this;
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}
sendMessage(Message msg)相关方法
public final boolean sendMessage(Message msg) {
    return sendMessageDelayed(msg, 0);
}

public final boolean sendEmptyMessage(int what) {
    return sendEmptyMessageDelayed(what, 0);
}

public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
    Message msg = Message.obtain();
    msg.what = what;
    return sendMessageDelayed(msg, delayMillis);
}
//...
//省略其他方法,基本上跟post系列方法是一一对应的
runWithScissors(final Runnable r, long timeout)

除了post(Runnable r)系列方法和sendMessage(Message msg)系列方法可以发送消息外,还有runWithScissors可以发送消息(Runnable对象)。

/**
     * Runs the specified task synchronously.
     * <p>
     * If the current thread is the same as the handler thread, then the runnable
     * runs immediately without being enqueued.  Otherwise, posts the runnable
     * to the handler and waits for it to complete before returning.
     * </p><p>
     * This method is dangerous!  Improper use can result in deadlocks.
     * Never call this method while any locks are held or use it in a
     * possibly re-entrant manner.
     * </p><p>
     * This method is occasionally useful in situations where a background thread
     * must synchronously await completion of a task that must run on the
     * handler's thread.  However, this problem is often a symptom of bad design.
     * Consider improving the design (if possible) before resorting to this method.
     * </p><p>
     * One example of where you might want to use this method is when you just
     * set up a Handler thread and need to perform some initialization steps on
     * it before continuing execution.
     * </p><p>
     * If timeout occurs then this method returns <code>false</code> but the runnable
     * will remain posted on the handler and may already be in progress or
     * complete at a later time.
     * </p><p>
     * When using this method, be sure to use {@link Looper#quitSafely} when
     * quitting the looper.  Otherwise {@link #runWithScissors} may hang indefinitely.
     * (TODO: We should fix this by making MessageQueue aware of blocking runnables.)
     * </p>
     *
     * @param r The Runnable that will be executed synchronously.
     * @param timeout The timeout in milliseconds, or 0 to wait indefinitely.
     *
     * @return Returns true if the Runnable was successfully executed.
     *         Returns false on failure, usually because the
     *         looper processing the message queue is exiting.
     *
     * @hide This method is prone to abuse and should probably not be in the API.
     * If we ever do make it part of the API, we might want to rename it to something
     * less funny like runUnsafe().
     */
public final boolean runWithScissors(final Runnable r, long timeout) {
    if (r == null) {
        throw new IllegalArgumentException("runnable must not be null");
    }
    if (timeout < 0) {
        throw new IllegalArgumentException("timeout must be non-negative");
    }
    //如果当前的线程和Handler所在的线程是同一个,则直接运行Runnable对象,
    //而不需要再进行入队-排队-出队的操作;
    if (Looper.myLooper() == mLooper) {
        r.run();
        return true;
    }
    //如果当前线程和Handler的线程不在同一个线程,
    //则会调用BlockingRunnable的postAndWait()方法
    BlockingRunnable br = new BlockingRunnable(r);
    return br.postAndWait(this, timeout);
}

//静态内部私有常量类,实现Runnable接口
private static final class BlockingRunnable implements Runnable {
    //真正需要执行的Rnnable对象
    private final Runnable mTask;
    //标识是否执行完毕
    private boolean mDone;

    public BlockingRunnable(Runnable task) {
        mTask = task;
    }

    @Override public void run() {
        try {
            mTask.run(); //运行mTask.Runnalbe
        } finally {
            synchronized(this) {
                //执行完以后,会把mDone标志位置为true,并唤醒其他阻塞线程
                mDone = true;
                notifyAll();
            }
        }
    }

    public boolean postAndWait(Handler handler, long timeout) {
        //把自身对象通过传入的handler.post()方法进行入队操作,
        //入队成功返回true,失败返回false;
        if (!handler.post(this)) {
            return false;
        }
        //加锁同步
        synchronized(this) {
            if (timeout > 0) {
                //计算超时时间,如果超时后还没有执行完,返回false,
                //并执行run中finally中的操作,
                //即把标志位置为true,并唤醒其他线程,此时run可能还没有执行完
                final long expirationTime = SystemClock.uptimeMillis() + timeout;
                while (!mDone) {
                    long delay = expirationTime - SystemClock.uptimeMillis();
                    if (delay <= 0) {
                        return false; // timeout
                    }
                    try {
                        wait(delay);
                    } catch(InterruptedException ex) {}
                }
            } else {
                //如果timeout小于等于0,会阻塞handler所在线程,
                //直到run方法内的finallay块被执行(会一直等到run执行完毕)
                while (!mDone) {
                    try {
                        wait();
                    } catch(InterruptedException ex) {}
                }
            }
        }
        return true;
    }
} 
getMain()方法
/** @hide */
@NonNull public static Handler getMain() {
    if (MAIN_THREAD_HANDLER == null) {
        MAIN_THREAD_HANDLER = new Handler(Looper.getMainLooper());
    }
    return MAIN_THREAD_HANDLER;
}

/** @hide */
@NonNull public static Handler mainIfNull(@Nullable Handler handler) {
    return handler == null ? getMain() : handler;
}

Handler中还有removeCallbacks()、removeMessage()、hasMessage()、toString()方法以及其重载方法,源码比较简单,这里就不做分析了,感兴趣的同学可以自行去查看源码。


4. Looper

Looper内部有一个消息队列MessageQueue,循环从MessageQueue中不断取出Message并对其进行分发。一个线程只能有一个Looper,由于Looper是线程局部变量,所以每个Looper中又有各自的MessageQueue。

成员变量
// sThreadLocal.get() will return null unless you've called prepare().
//静态域,线程局部变量,每个线程中有一个独立Looper对象。
//如果不调用prepare()方法,sThreadLocal.get()返回null
static final ThreadLocal < Looper > sThreadLocal = new ThreadLocal < Looper > ();
//静态域,主线程的Looper,由Looper class来维护
private static Looper sMainLooper; // guarded by Looper.class
//消息队列,每个Looper中有一个MessageQueue
final MessageQueue mQueue;
//Looper对象自身所在线程
final Thread mThread;
//打印对象及Tag
private Printer mLogging;
private long mTraceTag;
/* If set, the looper will show a warning log if a message dispatch takes longer than time. */
private long mSlowDispatchThresholdMs;
构造方法
private Looper(boolean quitAllowed) {
    mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();
}
prepare()方法
//公有方法,开发者只能调用这个方法进行Looper的初始化,
//可见开发者得到的Looper中的MessageQueue,是允许退出的
public static void prepare() {
    prepare(true);
}
//私有方法,开发者无法调用,而且对同一个线程重复调用
//prepare()方法会抛出异常
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初始化,虽然是公有方法,我们无法调用,
//因为系统启动的时候已经调用过了,如果再次调用,会抛异常
public static void prepareMainLooper() {
    prepare(false);
    synchronized(Looper.class) {
        if (sMainLooper != null) {
            throw new IllegalStateException("The main Looper has already been prepared.");
        }
        //把得到的主线程Looper赋值给sMainLooper 
        sMainLooper = myLooper();
    }
}
public static@Nullable Looper myLooper() {
    return sThreadLocal.get();
}
loop()方法
 //代码省去打印等其他无关逻辑
public static void loop() {
    //拿到本线程的sThreadLocal变量的值
    final Looper me = myLooper();
    //如果当前线程没有调用过prepare()方法,则me为null,抛出异常
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    //从me里获得本线程的MessageQueue对象
    final MessageQueue queue = me.mQueue;
    Binder.clearCallingIdentity();
    final long ident = Binder.clearCallingIdentity();
    //进入死循环,开始从MessageQueue中取出消息进行处理
    for (;;) {
        //取出消息,可能被阻塞
        Message msg = queue.next(); // might block
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            return;
        }
        try {
            //通过Message对象中的targe域获得发送该消息的Handler,
            //调用它的dispatchMessage()方法来处理对象
            msg.target.dispatchMessage(msg);
        } finally {
            if (traceTag != 0) {
                Trace.traceEnd(traceTag);
            }
        }
        final long newIdent = Binder.clearCallingIdentity();
        msg.recycleUnchecked();
    }
}

Looper还有quit(),quitSafely(),toString()等其他方法,感兴趣的同学可以自行查看源码;


5. 利用异步消息处理机制,主线程与子线程之间的通信

通过上述源码的详细分析,可以知道:

private static Handler handler = new Handler() {
    //主线程处理消息
    @Override public void handleMessage(Message msg) {
        //主线程根据Message进行逻辑处理
    }
};
class WorkThreadRunnable implements Runnable {
    //子线程发送相关消息
    @Override public void run() {
        Message message = Message.obtain();
        //在子线程中用在主线程中创建的Hander发送消息即可
        handler.sendMessage(message);
    }
}
 private Handler handler;

@Override 
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_handler_main_to_child);
    button = (Button) findViewById(R.id.button);
    button.setOnClickListener(new View.OnClickListener() {@Override public void onClick(View view) {
            Message message = Message.obtain();
            handler.sendMessage(message);
        }
    });
    new Thread(new WorkThreadRunnable()).start();

}

class WorkThreadRunnable implements Runnable {@Override public void run() {
        Looper.prepare();
        handler = new Handler() {@Override public void handleMessage(Message msg) {
                //接收到消息后,进行处理
            }
        };
        Looper.loop();
    }
}
     //创建子线程
class WorkThread extends Thread {
    private Looper looper; //取出该子线程的Looper
    public void run() {
        Looper.prepare(); //创建该子线程的Looper
        looper = Looper.myLooper(); //取出该子线程的Looper
        Looper.loop(); //只要调用了该方法才能不断循环取出消息
    }
}

private Handler mHandler;

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    thread = new WorkThread();
    thread.start();
    //创建Handler时把looper做入参,把Handler与Looper绑定在一起
    mHandler = new Handler(thread.looper) {
        public void handleMessage(android.os.Message msg) {
            //在子线程中处理消息的逻辑
        };
    };
    mHandler.senMessage(Message.obtain());
}

6. 异步消息处理机制使用不当可能导致的问题
内存泄漏

通常情况下,我们会在一个Activity/Fragment中使用消息处理机制进行线程间的通信,如果Handler为非静态内部类,则会引用外部类对象。当Activity/Fragment finish时,Handler可能并未执行完,则会引起Activity/Fragment的内存泄漏。故而所有调用Handler的地方,都使用静态内部类。如果Handler需要访问Activity/Fragemnt非静态成员/非静态方法,可以让Handler持有外部对象的弱引用;

private static class HandlerDemo extends Handler{
    private final WeakReference<Activity> mActivity;
    
    public HandlerDemo(Activvity mActivity) {
        this.mActivity = new WeakRefrence<Activity>(mActivity);
    }

   @Override
    public void handleMessage(Message msg) {
          //处理消息,在访问mActivity的时候要先进行判空
    }
}
资源被释放而导致的异常

当Activity/Fragment调用onDestroy()等回调方法后,会释放掉一些资源,而在Handler执行handleMessage()方法时,在访问Activity/Fragment的成员变量/方法时,可能会由于资源被释放而导致空异常。所以除了在对Activity/Fragment进行判空以外,还要对访问到的成员变量等进行判空操作,并且在onDestory()方法里把消息队列中的消息remove。

  @Override
  protected onDestroy() {\
      super.onDestory();
      //移除post的Runnable对象
      handler.removeCallback(postRunnable);
      //移除send的Message对象
      handler.removeMessage(what);
  }

7. 总结

通过上述源码分析,我们理解了Message、MessageQueue、Handler和Looper的实现细节,现在应该对Android异步消息处理机制的实现的细节、通信原理和可能带来问题都清楚了,如果还有什么疑问,大家可以自行查看源码。如果有写的不对的地方,欢迎进行指正和交流。

上一篇 下一篇

猜你喜欢

热点阅读