面试时常会被问:Android的线程间通信是怎么样的?
遇到这种问题首先要明白一点;Android是使用Java语言开发的,尽管现在已经是Kotlin的时代了,但Kotlin的底层仍旧是JVM虚拟机制,所以Java的各种线程类和线程池仍旧可用。但这只是线程,要说线程间通信的话首要想到的是Handler+线程类的实现方式,为此还专门衍生出了AsyncTask类,此外还有第三方的EventBus和新出的LiveEventBus,EventBus和LiveEventBus在GitHub上专门的用法,比较简单没什么好多说的。问这个问题大数情况下还是想听听你对Handler机制的理解。
所以在回答时要先说Handler是一种线程间通信机制,通过Handler可以将耗时操作放在子线程中完成,然后再在主线程中刷新结果。
Handler的四个要素:
- Message(消息):用于线程间传统数据的载体,说白了就是一个数据类。
- MessageQueue(消息队列):是一个单链表数据结构,不断的接收和取出消息,消息队列只和Handler打交道。
- Handler:负责消息的发送和处理(分成send和post两种)。
- Looper(循环器):用于创建消息队列,并让这个队列无限循环。
这样说完人家可能还不明白,所以我们可以形象的比喻这四个要素:
Handler(工人),Message(产品),MessageQueue(产品线履带),Looper(产品线发动机)。发动机启动后履带就开始转动,然后工人在一个叫“子线程”的车间把数据打包成一种叫“消息”的产品放到履带上,随着履带的转动,在“主线程”车间的工人再取出这个产品,把里面的数据填充到界面上。只是这个工人受累在两个车间之间来回跑。这个比喻够形象了吧!
handler.png
至此就带出了几个问题:
一个线程可以有几个Looper、几个MessageQueue、几个Handler?
一个Looper、一个MessageQueue、多个Handler。
当有多个Handler的时候怎么知道哪个Message属于哪个Handler?
Message类内部定义了一个target属性,用于标记出对应的Handler。
怎样创建一个Message对象?
可以直接new出来,但推荐用Message.obtain()或mHandler.obtainMessage(),这样可以复用已有的Message对象而减少创建对象时的开销。
在子线程中可以创建Handler吗?
可以,但必要先创建Looper对象,用Looper.prepare()方法,而在主线程中已经有了Looper对象所以不需要创建。参见可以在子线程实例化Handler对象吗
Handler的post方法需要传入一个Runnable对象,是否有新的线程被启动?
没有,其实post方法等价于sendMessage方法。这里的Runnable并没有被start,只是调用了run方法。
public final boolean post(@NonNull Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
Looper在主线程中启动了无限循环为什么不会阻塞主线程?
关于这个问题可以贴一堆的源代码,这里我就不贴了,贴代码的意义不大。简单的来说主线程就是main函数(对!就是public static void main(String[] args))所在的线程,而这个无限循环就是运行在这个main函数的最后,要没这个循环的话程序就执行完毕退出了。而这个循环也不是啥事都不干,它会不断的发送和Activity生命周期对应的消息给Handler处理。
最后讲一下内存泄露的问题。
例如:你在Activity中用Handler延时若干秒发送一个消息,结果在这个时间段内你关闭了Activity,表面上是关了,但Activity的引用却被Handler持有着,而Handler的引用又被Message持有着,Message还在延时中,所以内存泄露就产生了。
那要怎么解决?
- 一种方法是在Activity的onDestroy方法里调用mHandler.removeCallbacksAndMessages(null)。
- 另一种是在Handler中持有Activity的弱引用:
private static class MyHandler extends Handler {
private WeakReference<MainActivity> mWeakReference;
public MyHandler(MainActivity activity) {
mWeakReference = new WeakReference<>(activity);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
MainActivity mainActivity = mWeakReference.get();
...
mainActivity.mTextView.setText(msg.obj + "");
...
}
这里把MyHandler定义成静态内部类,静态内部类不持有外部类的引用,所以需要把MainActivity作为参数传进去,而且持有对象的弱引用。
点击链接加入群聊【口袋里的安卓】:861401732
或关注微信公众号:
qrcode_for_gh_31280308f3ef_258.jpg











网友评论