Android中可以通过Handler来更新主线程中UI的变化,更新UI只能在主线程中进行更新,而为了让其他线程也能控制UI的变化,Android提供了一种机制HandlerLooperMessageQueue一同协作来达到其他线程更新UI的目的。

一般我们会在主线程中通过如下方法定义一个Handler

private Handler mHandler = new Handler() {        @Override        public void handleMessage(Message msg) {            tv.setText("mHandler change UI");            super.handleMessage(msg);        }    };

一般都见不到LooperMessageQueue的,那么它们都是在哪里调用与如何协作的呢?在主线程不会显式的调用Looper而是会在ActivityThread.main方法中默认调用。

ActivityThread.main

public static void main(String[] args) {         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");        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());         // Make sure TrustedCertificateStore looks in the right place for CA certificates        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());         TrustedCertificateStore.setDefaultUserDirectory(configDir);         Process.setArgV0("");         Looper.prepareMainLooper();//创建Looper         ActivityThread thread = new ActivityThread();        thread.attach(false);         if (sMainThreadHandler == null) {            sMainThreadHandler = thread.getHandler();        }         if (false) {            Looper.myLooper().setMessageLogging(new                    LogPrinter(Log.DEBUG, "ActivityThread"));        }         // End of event ActivityThreadMain.         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);        Looper.loop();//开启Looper循环         throw new RuntimeException("Main thread loop unexpectedly exited");    }

如上代码,调用了Looper.prepareMainLooper()方法,在主线程中创建了一个Looper,不信的话我们再查看该方法做了什么

Looper

prepare

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));//创建Looper并赋给sThreadLocal    }     /**     * Initialize the current thread as a looper, marking it as an     * application's main looper. The main looper for your application     * is created by the Android environment, so you should never need     * to call this function yourself.  See also: {@link #prepare()}     */    public static void prepareMainLooper() {        prepare(false);        synchronized (Looper.class) {            if (sMainLooper != null) {                throw new IllegalStateException("The main Looper has already been prepared.");            }            sMainLooper = myLooper();        }    }         public static @Nullable Looper myLooper() {        return sThreadLocal.get();    }

prepareMainLooper方法中调用了prepare而通过prepare会发现它其实就是创建了一个Looper,并把它赋给了sThreadLocal。同时可以通过myLooper方法获取当前线程中的Looper。再来看下new Looper(quitAllowed)初始化了什么

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

在这里我们终于看到了MessageQueue了,它创建了一个MessageQueue。该消息队列就是用来保存后续的Message。再回到ActivityThread.main方法中,发现它调用了Looper.loop()是用来开启Looper循环的,监听消息队列MessageQueue中的消息。

loop

我们来看下Looper.loop()的源码:

public static void loop() {        final Looper me = myLooper();//获取Looper        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            final Printer logging = me.mLogging;            if (logging != null) {                logging.println(">>>>> Dispatching to " + msg.target + " " +                        msg.callback + ": " + msg.what);            }             final long traceTag = me.mTraceTag;            if (traceTag != 0) {                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));            }            try {                msg.target.dispatchMessage(msg);//通过Handler分发消息            } finally {                if (traceTag != 0) {                    Trace.traceEnd(traceTag);                }            }             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.recycleUnchecked();        }    }

loop中首先获取了当前所在线程的Looper,同时也获取到了Looper中的MessageQueue,说明Looper已经与当前的线程进行了绑定。在后面开启了一个for的死循环,发现它做的事件是不断的从消息队列中取出消息,最后都交给msg.target调用它的dispatchMessage方法,那么target又是什么呢?我们进入Message

Message

/*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中的dispatchMessage方法,对消息的分发处理。这样一来Handler就通过Looper联系上了Looper所绑定的线程,即为主线程。

Handler

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的初始化,它获取了它所处线程的Looper,同时也获取了Looper中的消息队列。当然如果所处线程的Looper为空的话就会抛出异常,这就解释了为什么在非主线程中创建Handler要分别调用Looper.prepareLooper.loop而主线程则不需要,因为它默认已经调用了。

dispatchMessage

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

回到前面,对于dispatchMessage的处理,首先判断msg.callback是否为空,这里callback通过上面的Message应该能知道他就是一个Runnable,如果不为空则直接调用Runnablerun方法。否则调用HandlerhandleMessage方法.而这个方法相信大家已经很熟悉了,对事件的处理都是在这个方法中执行的。因为通过前面我们已经知道了Handler已经联系上了主线程,所以handleMessage中的处理自然相对于在主线程中进行,自然也能更新UI了。通过这里我们能把Looper比作是一个桥梁,来连接Looper所在的线程与Handler之间的通信,同时管理消息队列MessageQueue中的消息。那么前面的Runnable又是如何不为空的呢?我们使用Handler有两种方法,一种是直接创建一个Handler并且重写它的handleMessage方法,而另一种可以通过Handler.post(Runnable)来使用,这样事件的处理自然就在run方法中实现。

上面介绍了Handler是如何联系上了需要操作的线程与对消息是如何取出与处理的。下面来谈谈消息是如何放入到Looper中的MessageQueue中的。

 sendMessageAtTime

通过Handler发送消息的方式很多,例如:sendMessagesendEmptyMessagesendMessageDelayed等,其实到最后他们调用的都是sendMessageAtTime方法。所以还是来看下sendMessageAtTime方法中的实现。

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

sendMessageAtTime则就是调用了enqueueMessage操作,看这方法名就知道是入队列操作了。

enqueueMessage

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {        msg.target = this;        if (mAsynchronous) {            msg.setAsynchronous(true);        }        return queue.enqueueMessage(msg, uptimeMillis);    }

果不其然直接调用了MessageQueue中的queue.enqueueMessage(msg, uptimeMillis)将消息加入消息队列,同时这段代码msg.target = this 将当前的Handler赋给了msg.target,这就是前面所说的Looper.loop方法中调用的Handler。这样就把消息放到了MessageQueue中,进而通过前面所讲的loop来取出消息进行相应的处理,这样就构成了整个对消息进行处理的系统。这也是使用Handler内部所发生的原理。好了HandlerLooperMessageQueue它们之间的联系基本就是这些了。我也简单画了张图希望有所帮助

总结

来总结下它们之间的流程。首先创建Handler而在Handler所处的线程中必须要有一个Looper,如果在主线程中默认帮我们实现了,其他线程必须调用Looper.prepare来创建Looper同时调用Looper.loop开启对消息的处理。每个Looper中都有一个MessageQueue它是用来存储Message的,Handler通过post或者send..等一系列操作通过Looper将消息放入到消息队列中,而Looper通过开启一个无限的循环来一直监听着消息的处理,不断从MessageQueue中取出消息,并交给与当前Looper所绑定的handlerdispatchMessage进行分发,最后根据情况调用Runnablerun或者HandlerHandlerMessage方法对消息进行最后的处理。

其它分享:https://idisfkj.github.io/arc...

关注

更多相关文章

  1. Android面试总结(持续更新修改)
  2. Android开发指南-框架主题-基础知识
  3. Android(安卓)之 使用嵌入式关系型SQLite数据库存储数据
  4. Android消息处理机制(Handler、Looper、MessageQueue与Message)
  5. Android(安卓)Hook Java
  6. Android开发中完全退出程序的三种方法
  7. MyEclipse安装Android(安卓)ADT 方法,亲测,能用
  8. Android中使用嵌入式关系型SQLite数据库存储数据
  9. Android导入一个工程时提示 Invalid project description的解决

随机推荐

  1. 使用AudioTrack播放PCM音频数据(android)
  2. Android(安卓)进程间通信(IPC)
  3. 【转】Android背景选择器Selector详解
  4. android widget
  5. Android(安卓)Studio 解决The SDK platfo
  6. Android(安卓)启动应用程序方式
  7. Android(安卓)Instrumentation Testing
  8. Android(安卓)基础知识
  9. [置顶] Android学好Shape不再依赖美工
  10. Android(安卓)事件冒泡及捕获