大佬教程收集整理的这篇文章主要介绍了详解Android中Handler的实现原理,大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
在 Android 中,只有主线程才能操作 UI,但是主线程不能进行耗时操作,否则会阻塞线程,产生 ANR 异常,所以常常把耗时操作放到其它子线程进行。如果在子线程中需要更新 UI,一般是通过 Handler 发送消息,主线程接受消息并且进行相应的逻辑处理。除了直接使用 Handler,还可以通过 View 的 post 方法以及 Activity 的 runOnUiThread 方法来更新 UI,它们内部也是利用了 Handler 。在上一篇文章 Android AsyncTask源码分析 中也讲到,其内部使用了 Handler 把任务的处理结果传回 UI 线程。
本文深入分析 Android 的消息处理机制,了解 Handler 的工作原理。
Handler
先通过一个例子看一下 Handler 的用法。
public class MainActivity extends AppCompatActivity { private static final int messaGE_TEXT_VIEW = 0; private TextView mTextView; private Handler mHandler = new Handler() { @Override public void handlemessage(message msg) { switch (msg.what) { case messaGE_TEXT_VIEW: mTextView.setText("UI成功更新"); default: super.handlemessage(msg); } } }; @Override protected void onCreate(Bundle savedInstanceStatE) { super.onCreate(savedInstanceStatE); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); mTextView = (TextView) findViewById(R.id.text_view); new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(3000); } catch (InterruptedException E) { e.printStackTrace(); } mHandler.obtainmessage(messaGE_TEXT_VIEW).send@R_715_10586@rget(); } }).start(); } }
上面的代码先是新建了一个 Handler的实例,并且重写了 handlemessage 方法,在这个方法里,便是根据接受到的消息的类型进行相应的 UI 更新。那么看一下 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; }
在构造方法中,通过调用 Looper.myLooper() 获得了 Looper 对象。如果 mLooper 为空,那么会抛出异常:"Can't create handler inside thread that has not called Looper.prepare()",意思是:不能在未调用 Looper.prepare() 的线程创建 handler。上面的例子并没有调用这个方法,但是却没有抛出异常。其实是因为主线程在启动的时候已经帮我们调用过了,所以可以直接创建 Handler 。如果是在其它子线程,直接创建 Handler 是会导致应用崩溃的。
在得到 Handler 之后,又获取了它的内部变量 mQueue, 这是 messageQueue 对象,也就是消息队列,用于保存 Handler 发送的消息。
到此,Android 消息机制的三个重要角色全部出现了,分别是 Handler 、Looper 以及 messageQueue。 一般在代码我们接触比较多的是 Handler ,但 Looper 与 messageQueue 却是 Handler 运行时不可或缺的。
Looper
上一节分析了 Handler 的构造,其中调用了 Looper.myLooper() 方法,下面是它的源码:
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
这个方法的代码很简单,就是从 sThreadLocal 中获取 Looper 对象。sThreadLocal 是 ThreadLocal 对象,这说明 Looper 是线程独立的。
在 Handler 的构造中,从抛出的异常可知,每个线程想要获得 Looper 需要调用 prepare() 方法,继续看它的代码:
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)); }
同样很简单,就是给 sThreadLocal 设置一个 Looper。不过需要注意的是如果 sThreadLocal 已经设置过了,那么会抛出异常,也就是说一个线程只会有一个 Looper。创建 Looper 的时候,内部会创建一个消息队列:
private Looper(Boolean quitAllowed) { mQueue = new messageQueue(quitAllowed); mThread = Thread.currentThread(); }
现在的问题是, Looper看上去很重要的样子,它到底是干嘛的?
回答: Looper 开启消息循环系统,不断从消息队列 messageQueue 取出消息交由 Handler 处理。
为什么这样说呢,看一下 Looper 的 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.recycleUnchecked(); } }
这个方法的代码有点长,不去追究细节,只看整体逻辑。可以看出,在这个方法内部有个死循环,里面通过 messageQueue 的 next() 方法获取下一条消息,没有获取到会阻塞。如果成功获取新消息,便调用 msg.target.dispatchmessage(msg),msg.target是 Handler 对象(下一节会看到),dispatchmessage 则是分发消息(此时已经运行在 UI 线程),下面分析消息的发送及处理流程。
消息发送与处理
在子线程发送消息时,是调用一系列的 sendmessage、sendmessageDelayed 以及 sendmessageAtTime 等方法,最终会辗转调用 sendmessageAtTime(message msg,long uptimeMillis),代码如下:
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); }
这个方法就是调用 enqueuemessage 在消息队列中插入一条消息,在 enqueuemessage总中,会把 msg.target 设置为当前的 Handler 对象。
消息插入消息队列后, Looper 负责从队列中取出,然后调用 Handler 的 dispatchmessage 方法。接下来看看这个方法是怎么处理消息的:
public void dispatchmessage(message msg) { if (msg.callBACk != null) { handleCallBACk(msg); } else { if (mCallBACk != null) { if (mCallBACk.handlemessage(msg)) { return; } } handlemessage(msg); } }
首先,如果消息的 callBACk 不是空,便调用 handleCallBACk 处理。否则判断 Handler 的 mCallBACk 是否为空,不为空则调用它的 handlemessage方法。如果仍然为空,才调用 Handler 自身的 handlemessage,也就是我们创建 Handler 时重写的方法。
如果发送消息时调用 Handler 的 post(Runnable r)方法,会把 Runnable封装到消息对象的 callBACk,然后调用 sendmessageDelayed,相关代码如下:
public final Boolean post(Runnable r) { return sendmessageDelayed(getPostmessage(r),0); } private static message getPostmessage(Runnable r) { message m = message.obtain(); m.callBACk = r; return m; }
此时在 dispatchmessage中便会调用 handleCallBACk进行处理:
如果在创建 Handler时,直接提供一个 CallBACk 对象,消息就交给这个对象的 handlemessage 方法处理。CallBACk 是 Handler 内部的一个接口:
以上便是消息发送与处理的流程,发送时是在子线程,但处理时 dispatchmessage 方法运行在主线程。
总结
至此,Android消息处理机制的原理就分析结束了。现在可以知道,消息处理是通过 Handler 、Looper 以及 messageQueue共同完成。 Handler 负责发送以及处理消息,Looper 创建消息队列并不断从队列中取出消息交给 Handler, messageQueue 则用于保存消息。
以上是大佬教程为你收集整理的详解Android中Handler的实现原理全部内容,希望文章能够帮你解决详解Android中Handler的实现原理所遇到的程序开发问题。
如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。