抽烟的青蛙的专栏

当在面试的时候问到Handler的消息机制的时候,虽然能够能说出来些什么。但总感觉心里空空的。工作之余网上找了一下加看了一下源码,记录一下,以便日后查看.

1.了解Handler消息机制之前先了解与消息有关的几个类:

a.Handler:消息的处理者。

b.Looper:MessageQueue的管理者。

d.Message:消息对象。

2.顺着一个程序的思路开始,要想进行进程间的通信,,我们首先要创建一个Handler:

private Handler mHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {// TODO Auto-generated method stubsuper.handleMessage(msg);switch (msg.what) {case value:break;default:break;}}};在new Handler的时候有没有做什么呢?我们来看一下Handler的构造函数: public Handler() {this(null, false);}public Handler(Callback callback, boolean async) {if (FIND_POTENTIAL_LEAKS) {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());}}mLooper = Looper.myLooper();if (mLooper == null) {throw new RuntimeException("Can't create handler inside thread that has not called Looper.prepare()");}mQueue = mLooper.mQueue;mCallback = callback;mAsynchronous = async;}在Handler的构造函数中我们可以看到mLooper = Looper.myLooper();Looper.myLooper()做了什么能?继续往下看:static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); public static Looper myLooper() {return sThreadLocal.get();}是从ThreadLocal中get得到looper!我们好像从开始就没有初始化Looper吧。更不用说将Looper set到ThreadLocal中了,到这里主要是Looper的事情了。先将Handler放一下,来看一下Looper。

3.Looper

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);Process.setArgV0("<pre-initialized>");Looper.prepareMainLooper();if (sMainThreadHandler == null) {sMainThreadHandler = new Handler();}ActivityThread thread = new ActivityThread();thread.attach(false);if (false) {Looper.myLooper().setMessageLogging(newLogPrinter(Log.DEBUG, "ActivityThread"));}Looper.loop();throw new RuntimeException("Main thread loop unexpectedly exited");}我们可以找到Looper.prepareMainLooper();Looper.loop();这行代码,继续看看它做了什么: public static void prepareMainLooper() {prepare();setMainLooper(myLooper());myLooper().mQueue.mQuitAllowed = false;}public static void prepare() {if (sThreadLocal.get() != null) {throw new RuntimeException("Only one Looper may be created per thread");}sThreadLocal.set(new Looper());} public static void loop() {Looper me = myLooper();if (me == null) {throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");}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();while (true) {Message msg = queue.next(); // might blockif (msg != null) {if (msg.target == null) {// No target is a magic identifier for the quit message.return;}long wallStart = 0;long threadStart = 0;// This must be in a local variable, in case a UI event sets the loggerPrinter logging = me.mLogging;if (logging != null) {logging.println(">>>>> Dispatching to " + msg.target + " " +msg.callback + ": " + msg.what);wallStart = SystemClock.currentTimeMicro();threadStart = SystemClock.currentThreadTimeMicro();}msg.target.dispatchMessage(msg);if (logging != null) {long wallTime = SystemClock.currentTimeMicro() – wallStart;long threadTime = SystemClock.currentThreadTimeMicro() – threadStart;logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);if (logging instanceof Profiler) {((Profiler) logging).profile(msg, wallStart, wallTime,threadStart, threadTime);}}// 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();}}}好了到这里可以看出来了sThreadLocal.get() != null的话会出RuntimeException,所以每一个Thread只能对应一个Looper,sThreadLocal.set(new Looper());所以方法。这里来总结一下Looper.prepare()和Looper.loop()的作用:prepare函数所做的事情只是在全局的sThreadLocal中存放了个新的Looper,new Looper时赋值了mQueue和mThread,也就是说循环获取消息队列中得下一条消息(Message msg = queue.next()),如果调用的queue.next返回的msg为null则立即结束此线程(if (msg.target == null) { return; }),如果不为null则调用msg.target.dispatchMessage(此target为handler实例,即在当前线程调用到了handler的handlerMessage,如果找不到的话ctrl+单击鼠标左键),dispatchMessage()又干了什么呢: public void dispatchMessage(Message msg) {if (msg.callback != null) {handleCallback(msg);} else {if (mCallback != null) {if (mCallback.handleMessage(msg)) {return;}}handleMessage(msg);}}看到handleMessage(msg);我想应该就明白了吧!等等,好像没有Message和MessageQueue有什么关系。奥!我们光实例化了Handler,还没有sendmessage呢,继续看 public final boolean sendMessage(Message msg){return sendMessageDelayed(msg, 0);} public final boolean sendMessageDelayed(Message msg, long delayMillis){if (delayMillis < 0) {delayMillis = 0;}return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);} 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);}    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {        msg.target = this;        if (mAsynchronous) {            msg.setAsynchronous(true);        }        return queue.enqueueMessage(msg, uptimeMillis);    }添加到消息队列中,MessageQueue queue = mQueue??mQueue什么时候初始化的啊?在Looper.prepare() new Looper()的时候,不信来看: private Looper() {mQueue = new MessageQueue();mRun = true;mThread = Thread.currentThread();}{publicHandlermHandler;{Looper.prepare();//其它需要处理的操作Looper.loop();}} 好了!Handler的主要运作已经明白了,来总结一下:莫找借口失败,只找理由成功。

抽烟的青蛙的专栏

相关文章:

你感兴趣的文章:

标签云: