上一节咱们讲解了Handler的基本使用方法,也是平时你们用到的最多的使用方式。那么本节让咱们来学习一下Handler的工做原理吧!!!android
咱们知道Android中咱们只能在ui线程(主线程)更新ui信息,那么大家知道为何只能经过Handler机制更新ui吗?其实最根本的目的就是解决多线程并发的问题。面试
假设在一个Activity中有多个线程去更新ui,而且都没有加锁,那么会是什么样子?多线程
致使的结果就是更新界面错乱。并发
若是对更新ui的操做都进行加锁处理的话又产生什么问题哪?async
性能降低。ide
处于对以上问题的考虑,Android给咱们提供了一套更新ui的机制,咱们只须要遵照这样的机制就能够了。根本不用去关心多线程问题,由于全部更新ui的操做,都是在主线程的消息队列当中经过轮训处理的。oop
<一>Handler机制的角色和职责源码分析
1 MessageQueue 消息队列性能
存储消息的容器,能够向其中添加、取出消息。遵循先进先出的原则。学习
2 Handler
负责将消息发向消息容器即MessageQueue中。
3 Looper 轮训器
经过调用自身的loop方法,不断的从消息队列当中取出消息并发送给target(即handler)处理消息。当消息队列当中没有轮训消息时,它就处于堵塞状态。
来个实际图来看一下Handler的工做原理:
<二>Handler机制工做原理分析
Handler机制要想起做用有三个步骤:
1 建立Looper
2 建立Handler
3 调用Looper的loop方法,循环消息
下面让咱们来看看android中,如何去遵循这三点的,在那以前,先普及一下一个知识:
默认整个应用程序,都是经过ActivityThread类启动的,在ActivityThread类当中,负责建立咱们全部的Activity,并回调每一个Activity中的生命周期方法。在ActivityThread类中,默认会去建立一个线程,这个线程叫作main线程(主线程)。全部的应用程序,更新ui的操做,都是在这个main线程中进行的。
建立Looper和调用loop方法的工做,Android SDK 已经为咱们作好了,因此咱们在平时使用的时候,只须要建立Handler并发送消息便可。下面咱们跟随Android源码看看它是怎么作的。入口是ActivityThread的main方法。
跟进Looper的prepareMainLooper方法
跟进prepare方法
这里咱们须要对ThreadLocal类进行一下解释,ThreadLocal在咱们的线程当中用于去保存一些变量信息,默认状况下,建立一个与线程相关的一个对象,是经过threadLocal存储的,threadLocal有set和get方法,set是把变量设置到threadLocal当中 ,get方法是获取出来。由于当前线程是ui线程,默认状况下threadLocal是没有存储的,因此为null,因此不走if而是new Looper对象以后在存储,下面咱们在看看初始化Looper的时候作了哪些事情!
咱们看到,在建立Looper轮训器的时候,自动的建立了消息队列MessageQuene。也就是说默认的状况下,android为咱们自动建立了主线程的Looper和MessageQuene。
那么Handler怎么和咱们的MessageQuene消息队列联系在一块儿的那?由于以前不是说handler发出的消息是发送到消息队列中了吗?
缘由还要看咱们在建立Handler的时候作了那些事情,跟进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方法
public static @Nullable Looper myLooper() { return sThreadLocal.get(); }
看到了什么?sThreadLocal是否是很熟悉,没错它就是ThreadLocal对象。默认状况下android为咱们建立了主线程Looper对象并存储在sThreadLocal中,因此此处返回的就是主线程的Looper对象,也就是说咱们在建立Handler的时候,它就和消息队列关联起来了。
那么当咱们使用handler发送消息的时候,无论使用哪种方法,一步一步跟进源码发现最终调用的都是Handler的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); }
看代码可知,在发送消息的时候消息队列不能为null,继续跟进enqueueMessage方法
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
能够看到,消息最终发送到了消息队列当中。那么消息是怎么轮训的那?前面已经提过,是经过Looper的loop方法,那么来看看吧!!!
能够看到loop方法里面的机制就是一个死循环,不断的从消息队列中取出消息,而后发送给target(handler对象)的dispatchMessage方法,跟进去!!!
通常状况下咱们发送消息的时候没有给Message的callback赋值,因此第一个if条件不知足。下面的mCallback是在咱们初始化Handler的时候才被初始化,Handler初始化有一种方法Handler(Callback callback),此处的参数就是给mCallback赋值的。咱们通常初始化Handler的时候使用的是空参数的构造器,因此致使mCallback未被初始化,因此会直接走handleMessage(msg)方法,也就是咱们初始化Handler时重写的handleMessage方法。至此,Handler工做的机制就开始工做了,你、了解了吗?
下面让咱们看看若是咱们选择的是带Callback参数的初始化方式逻辑又会是什么样那,请看初始化代码:
Handler mHandler = new Handler(new Handler.Callback() { @Override public boolean handleMessage(Message msg) { Log.d(TAG,"callback参数-------handleMessage"); return true;//此处的返回值会影响下面的handleMessage方法是否调用 //false 调用 //true 不调用 } }){ @Override public void handleMessage(Message msg) { Log.d(TAG,"重写handler的-------handleMessage方法"); super.handleMessage(msg); } };
根据上面的源码分析咱们知道此处Callback参数中的handleMessage方法的返回值会影响到下面第二个handleMessage方法是否调用。通过验证,return true 则不调用 ,return false则调用。
最会经过一张图,看一下Handler的原理:
更形象一点,能够看下图:
好了,Android中的Handler机制工做原理我已经介绍完毕!!!参考了幕课网中《Android面试常客Handler详解》,你们若是没有明白能够去该网站自行学习。下篇我将介绍如何在子线程建立Handler。