Android消息机制

来源:互联网 发布:防范sql注入攻击的方法 编辑:程序博客网 时间:2024/06/10 17:40

消息机制本质上就是handler的工作机制,这里涉及到handler,message queue , looper ,Thread Local 等知识,按照惯例先来了解基础知识。

Thread Local

这是一个用于线程内部数据存储的类是一个泛型类,在主线程创建的一个Thread Local 对象在可以使用threadLocal.set()在子线程赋值,也可以在threadLocal.get()子线程取得数据,即可以在不同线程的赋值,但在不同线程的获取的值只是在该线程下赋予的值。

set()方法通过获取当前线程内部的ThreadLocal.Values类对象localValues,进行存数据。

Values类内部有一个数组,该数组实现了类似hashTable的功能,能以ThreadLocal对象为键进行存取数据,因此values的put方法就能存取当前线程的threadLocal 数据。

/**     * Sets the value of this variable for the current thread. If set to     * {@code null}, the value will be set to null and the underlying entry will     * still be present.     *     * @param value the new value of the variable for the caller thread.     */    public void set(T value) {        Thread currentThread = Thread.currentThread();        Values values = values(currentThread);        if (values == null) {            values = initializeValues(currentThread);        }        values.put(this, value);    }
/**         * Sets entry for given ThreadLocal to given value, creating an         * entry if necessary.         */        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;                }            }        }

看一下values()方法,他获取了当前线程的localValues,那去看看Thread的localValues对象,就只有声明

Values values(Thread current) {        return current.localValues;    }

get()方法类似,获取当前线程的Values对象,读取数组中的数据。

/**     * Returns the value of this variable for the current thread. If an entry     * doesn't yet exist for this variable on this thread, this method will     * create an entry, populating the value with the result of     * {@link #initialValue()}.     *     * @return the current value of the variable for the calling thread.     */    @SuppressWarnings("unchecked")    public T get() {        // Optimized for the fast path.        Thread currentThread = Thread.currentThread();        Values values = values(currentThread);        if (values != null) {            Object[] table = values.table;            int index = hash & values.mask;            if (this.reference == table[index]) {                return (T) table[index + 1];            }        } else {            values = initializeValues(currentThread);        }        return (T) values.getAfterMiss(this);    }

总结一下:threadLocal获取了线程的Values数组,用该数组存取了自己的数据,因为每个线程的Values数组是不一样的,因此同一个ThreadLocal对象在不同线程的中可以有不一样的数据,本质上这些数据都是保存在线程内部的(即Values中)。

messageQueue

消息队列是基于单链表实现的。主要操作时入队,出队,单链表能快速的进行插入、删除、移动,都是线程同步的。

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.");        }        synchronized (this) {            if (mQuitting) {                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;            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;    }

消息入队是按照when属性进行排序的,使用链表的直接插入排序。

Looper

看一下prepare()

/** Initialize the current thread as a looper.      * This gives you a chance to create handlers that then reference      * this looper, before actually starting the loop. Be sure to call      * {@link #loop()} after calling this method, and end it by calling      * {@link #quit()}.      */    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));    }

在prepare()方法中创建了Looper对象,并将其保存在了线程的ThreadLocal中,这样创建handler后,Looper.loop()就能在当前线程的ThreadLocal中获取到looper,再看看Looper()的构造函数。

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

构造函数中创建了MessageQueue和保存了当前线程,这样消息机制的三大要素就齐全了。但他们是怎么关联的呢?

看看loop()

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            Printer logging = me.mLogging;            if (logging != null) {                logging.println(">>>>> Dispatching to " + msg.target + " " +                        msg.callback + ": " + msg.what);            }            msg.target.dispatchMessage(msg);            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.recycle();        }    }
public static Looper myLooper() {        return sThreadLocal.get();    }

loop()将looper,messageQueue,handler相互关联起来。
looper只有调用了loop()才能真正起作用。该方法获取到了Looper对象之后从looper中取出MessageQueue这才能开启消息循环,从消息队列中获取消息,之后才能将消息分发给handler处理。

loop方法是个死循环循环内调用messagequeue的next()不断取消息,只有msg是null时才会退出,而只有当looper调用quit时才会有msg==null。MessageQueue的next()方法也是个死循环,next()方法用于不断的取下一条消息。没有消息会阻塞。
quit()时会退出。

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;                }                。。。。。。    }

取得消息后,调用msg.target.dipatchmessage(),target就是handler对象,这样就在创建handler的线程中处理消息了。

看看Message类的成员

public final class Message implements Parcelable {    public Object obj;    /**     * Optional Messenger where replies to this message can be sent.  The     * semantics of exactly how this is used are up to the sender and     * receiver.     */    public Messenger replyTo;    /** If set message is in use */    /*package*/ static final int FLAG_IN_USE = 1 << 0;    /** If set message is asynchronous */    /*package*/ static final int FLAG_ASYNCHRONOUS = 1 << 1;    /** Flags to clear in the copyFrom method */    /*package*/ static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE;    /*package*/ int flags;    /*package*/ long when;    /*package*/ Bundle data;    /*package*/ Handler target;         /*package*/ Runnable callback;       // sometimes we store linked lists of these things    /*package*/ Message next;

Handler工作原理

handler的post和send系列方法,post是通过send来实现的,send方法()向消息队列插入一条消息,在消息队列中消息是根据when属性排列的。在looper获取到消息后就会调用handler的dispatchmessage(),然后调用handlermessage或者runnable的run方法,

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

根据上面的message的成员知道,callback是runnable对象,mCallback是handler的成员如果使用下面的构造方法就会有没Callback!=null

public Handler(Looper looper, Callback callback, boolean async) {        mLooper = looper;        mQueue = looper.mQueue;        mCallback = callback;        mAsynchronous = async;    }

如果不想创建handler的子类实现handlmessage方法就可以使用上面的构造方法创建handler,

最后一个handlermessage当然就是我们创建handler是实现的handlemessage()

主线程的消息循环

Android的主线程是ActivityThread,入口时main()

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

看到MAIN函数很简洁,调用了looper的preparemainlooper(),创建了handler,调用了looper.loop()

activityThread通过ApplicationTread和AMS进程通信,AMS完成请求后回调ApplicationThread中的Binder的方法,ApplicationThread的收到消息后通过handler切换到ActivityThread中执行

3 0