您的位置:首页 > 移动开发 > Android开发

Android消息机制

2016-07-17 15:46 501 查看
消息机制本质上就是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中执行
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android 线程