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中执行
- Android消息机制(Handler机制)
- android Handler机制 消息机制
- Android 消息处理机制
- Android消息机制
- android 消息机制
- Android消息机制(一)
- Android消息处理机制
- Android消息处理机制
- Android消息机制(一)
- Android 中的消息机制
- Android 消息通知机制
- Android消息机制学习
- Android消息机制(1)
- Android消息机制
- android消息机制
- Android消息机制
- Android的消息机制
- android消息处理机制
- android--handler机制的原理
- 线程池介绍
- JavaScript-DOM
- 函数指针的使用
- macbook上的远程桌面
- Android消息机制
- java设计模式-克隆模式(复制模式)
- 策略设计模式
- Web.xml详解
- 浙大PAT 4-09. 笛卡尔树 (解题思路)
- dubbo+zookeeper服务器配置
- Android面试经验(转载)
- 朴素贝叶斯方法(Naive Bayes)
- 自定义Spark Streaming接收器(Receivers)