Android之Handler面试题(1)
1、一个线程有几个Handler?
一个线程可以有多个Handler
2、一个线程有几个Looper?
一个线程只有一个Looper
3.如何解决Handler的内存泄露问题呢?
Handler的内存泄露主要是非静态内部类持有外部类的引用造成的。所以可以把 Handler 声明为静态内部类,同时在Handler
中添加一个对 Activity 的弱引用,这样 GC 就能把 Activity 及时的回收,从而杜绝了内存泄露的问题。
代码如下:
static class ActivityHandler extends Handler {
WeakReference<Activity> activityReference;
ActivityHandler(Activity activity) {
activityReference = new WeakReference<Activity>(activity);
}
@Override
public void handleMessage(Message msg) {
final Activity activity = activityReference.get();
if (activity != null) {
//...
}
}
}
4.为什么主线程可以new Handler()呢?如果想要在子线程中new Handler()需要做些什么准备?
主线程 ActivityThread 的 main 函数已经执行了 Looper.prepareMainLooper() 和 Looper.loop(),所以我们可以直接在主线程 new Handler() 了。如果要在子线程中 new Handler(),就必须在子线程中执行 prepare() 和 loop()。
5.子线程中维护的Looper,消息队列无消息的时候的处理方案是什么?有什么用?
子线程中维护的Looper,消息队列无消息的时,可以调用Looper的quitSafely()或quit()函数,使得Looper结束死循环,并且起到释放内存和线程的作用。
6.多个Handler往MessageQueue中添加数据,内部是如何确保线程安全的?
在往MessageQueue添加数据时,使用synchronized线程锁,在往MessageQueue取数据时,也使用synchronized线程锁,所以MessageQueue通过synchronized来保证了线程的安全性,保证消息不会混乱。
7.Handler所发送的Delayed消息时间准确吗?
Handler所发送的Delayed消息时间基本准确,但不完全准确。因为多个线程去访问MessageQueue时,在MessageQueue添加或取出Message时都会加锁,当第一个线程还没有访问完成时,第二个线程就无法使用,所以实际的时间会被延迟。
8.使用Handler的postDelay后消息队列将会有怎样的变化?
使用Handler的postDealy后消息队列可能会进行重新排序。消息队列里消息按执行先后时间进行排序,先执行的在前,后执行的在后。postDealy发送的消息会根据延迟时间与消息队列里存在的消息的执行时间进行比较,然后寻找插入位置插入消息。
9.Looper死循环为什么不会导致应用卡死?
点击Launch桌面的图标第一次启动Activity时,最终会执行 ActivityThread 的 main 方法,在main方法里面创建
Looper 和 MessageQueue 处理主线程的消息,然后 Looper.loop() 方法通过创建一个for死循环来处理消息。Looper.loop()本身不会导致应用卡死,在无消息时会进行休眠。真正卡死主线程操作的是在回调方法onCreate、onStart、onResume等操作时间过长,会导致掉帧甚至ANR。