Handler的相关博客太多了,随便一搜都一大把,但是基本都是上来就贴源码,讲姿势,短时间不太好弄明白整体的关系,和流程.
本文就以生活点餐的例子再结合源码原理进行解析。希望对你有一点帮助。 来,咱们进入角色。
Handler,Looper,MessageQueue,Message的全程协作的关系就好比一个餐厅的整体运作关系
接下来我们回顾下我们餐厅点餐的场景,餐厅点餐分为标准点餐和特殊点餐,我们分解来看。
标准流程
特殊流程
总结
一家店可以有多个点餐员,但是厨师长只能有一个。打单机也只能有一个。
映射到以上场景中
根据以上的例子我们类比看下源码,充分研究下整个机制的流程,和实现原理。
Looper的工作流程
ActivityThread.main();//初始化入口
1. Looper.prepareMainLooper(); //初始化
Looper.prepare(false); //设置不可关闭
Looper.sThreadLocal.set(new Looper(quitAllowed)); //跟线程绑定
1.1.Looper.mQueue = new MessageQueue(quitAllowed); //Looper和MessageQueue绑定
1.2.Looper.mThread = Thread.currentThread();
2. Looper.loop();
2.1.myLooper().mQueue.next(); //循环获取MessageQueue中的消息
nativePollOnce(); //阻塞队列
native -> pollInner() //底层阻塞实现
native -> epoll_wait();
2.2.Handler.dispatchMessage(msg);//消息分发
myLooper().mQueue.next()实现原理
Handler.dispatchMessage(msg)实现原理
Hander发送消息的流程
1.Handler handler = new Handler();//初始化Handler
1.Handler.mLooper = Looper.myLooper();//获取当前线程Looper。
2.Handler.mQueue = mLooper.mQueue;//获取Looper绑定的MessageQueue对象。
2.handler.post(Runnable);//发送消息
sendMessageDelayed(Message msg, long delayMillis);
sendMessageAtTime(Message msg, long uptimeMillis);
Handler.enqueueMessage();//Message.target 赋值为this。
Handler.mQueue.enqueueMessage();//添加消息到MessageQueue。
MessageQueue.enqueueMessage()方法实现原理
接下来该面试官问了
经常有人问为什么主线程的Looper阻塞不会导致ANR?
以上的所有内容均围绕原理,源码,接下来我们举几个特殊场景的例子
new Thread(new Runnable() {
@Override
public void run() {
Handler handler = new Handler();
}
}).start();
以上代码会报以下下错误
java.lang.RuntimeException: Can't create handler inside thread Thread[Thread-2,5,main] that has not called Looper.prepare()
at android.os.Handler.<init>(Handler.java:207)
at android.os.Handler.<init>(Handler.java:119)
at com.example.test.MainActivity$2.run(MainActivity.java:21)
at java.lang.Thread.run(Thread.java:919)
public Handler(Callback callback, boolean async) {
...省略若干代码
//通过 Looper.myLooper()获取了mLooper 对象,如果mLooper ==null则抛异常
mLooper = Looper.myLooper();
if (mLooper == null) {
//可以看到异常就是从这报出去的
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
public static @Nullable Looper myLooper() {
//而myLooper()是通过sThreadLocal.get()获取的,那sThreadLocal又是个什么鬼?
return sThreadLocal.get();
}
//可以看到sThreadLocal 是一个ThreadLocal<Looper>对象,那ThreadLocal值从哪赋值的?
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
//sThreadLocal 的值就是在这个方法里赋值的
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));
}
那子线程怎么创建Handler呢?只需在new Handler()之前调用下Looper.prepare()即可。
//我们看下ActivityMain的入口main方法,调用了 Looper.prepareMainLooper();
public static void main(String[] args) {
...
Looper.prepareMainLooper();
...
}
//看到这一下就明白了,原来主线程在启动的时候默认就调用了prepareMainLooper(),而在这个方法中调用了prepare()。
//提前将sThreadLocal 进行赋值了。
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 class HandlerActivity extends AppCompatActivity {
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler);
handler.sendEmptyMessageDelayed(1,5000);
}
}
大致意思就说 “由于这个处理程序被声明为一个内部类,它可以防止外部类被垃圾回收。如果处理程序正在对主线程以外的线程使用Looper或MessageQueue,则不存在问题。如果处理程序正在使用主线程的Looper或MessageQueue,则需要修复处理程序声明,如下所示:将处理程序声明为静态类;并且通过WeakReference引用外部类”。
我们来写一种正确的写法
public class HandlerActivity extends AppCompatActivity {
MyHandler handler = new MyHandler(this);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler);
handler.sendEmptyMessageDelayed(1,5000);
}
private static class MyHandler extends Handler{
private WeakReference<HandlerActivity> activityWeakReference;
public MyHandler(HandlerActivity activity) {
activityWeakReference = new WeakReference<>(activity);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
}
}
4. 补充个小知识点,啥是隐式引用?
注意 : 不是所有内部类都建议使用静态内部类,只有在该内部类中的生命周期不可控的情况下,建议采用静态内部类。其他情况还是可以使用非静态内部类的。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。