1.机制学习
1.1Handler定义
发送并处理 与线程的消息队列关联的Message和Runnable
1.2基本用法
1、Message.obtain() 从消息池取得Message
2、Handler().sendMessage(msg) 发送消息
3、Handler().post 将Runnable包装成Message发送
以下提供一个结构代码
import android.os.Handler;
import android.os.Message;public class HandlerTestActivity extends AppCompatActivity {private Handler mHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {switch(msg.what) {case 1:// do somethingbreak;}}};protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);setContentView(R.layout.activity_handler_test);// message形式sendMessage();// Runnable形式postRunnable();}private void sendMessage() {Message msg = Message.obtain(); msg.what = 1; mHandler.sendMessage(msg);}private void postRunnable() {mHandler.post(new Runnable() { @Override public void run() { // do something} });}
}
1.3相关类
Message是Handler发送的消息实体
MessageQueue是用来将消息按顺序排队的队列
Looper本质就是一个循环,不停的从MessageQueue中取出消息然后处理
1.4Handler内部运行机制
- 首先,创建一个Message开始的,交给Handler对象发送,sendMessage和sendMessageDelay最终都是在底层调用了sendMessageAtTime()方法,将Message对象放入MessageQueue中的。
- 之后,由Looper的loop()循环从MessageQueue中取出Message对象,调用message.getTarget()获取到发送消息的Handler对象,然后再调用handler.dispatchMessage()方法将信息分发给对应handler执行。
- 最后,Handler在dispatchMessage()方法中判断是否有callback 存在,存在则执行callback的onMessageHandler(),最终交由Message.callback执行;否则则执行handler的onMessageHandler()方法。
1.5消息队列MessageQueue存储方式
单链表结构,逻辑上属于线性结构,存储(物理)上属于链式结构
头尾元素易于添加和删除
随机存储,顺序访问
2.面试问题经验总结
-
Handler的实现原理: Handler内部通过与Looper和MessageQueue的配合,实现了消息处理和线程间通信的功能。
-
子线程中能不能直接new一个Handler,为什么主线程可以: 子线程中不能直接new一个Handler,因为子线程默认没有Looper,而Handler的构造函数中需要传入一个Looper对象。主线程可以是因为主线程默认有与之关联的Looper。
-
主线程的Looper第一次调用loop方法,什么时候,哪个类: 主线程的Looper第一次调用loop方法是在ActivityThread类的main方法中。
-
Handler导致的内存泄露原因及其解决方案: Handler持有外部类的引用可能导致内存泄露,解决方案可以使用弱引用或者在不需要Handler时及时removeCallbacksAndMessages(null)。
-
一个线程可以有几个Handler,几个Looper,几个MessageQueue对象: 一个线程可以有多个Handler,但通常只有一个Looper和一个MessageQueue对象。
-
Message对象创建的方式有哪些 & 区别?Message.obtain()怎么维护消息池的: Message对象的创建方式包括new Message()和Message.obtain(),区别在于Message.obtain()会从消息池中获取Message对象,维护消息池是通过一些静态方法来实现的。
-
Handler有哪些发送消息的方法: Handler的发送消息的方法包括sendMessage(Message msg)、sendMessageDelayed(Message msg, long delayMillis)、sendMessageAtTime(Message msg, long uptimeMillis)等。
-
Handler的post与sendMessage的区别和应用场景: post方法是sendMessage方法的封装,post方法会自动将Runnable包装成Message对象发送,适用于不需要传递消息数据的情况。
-
handler postDealy后消息队列有什么变化,假设先 postDelay 10s, 再postDelay 1s, 怎么处理这2条消息: 先postDelay 10s的消息会在消息队列中排在先,后postDelay 1s的消息会在其后。
-
MessageQueue是什么数据结构: MessageQueue是一个基于链表的数据结构,用于存储消息队列。
-
Handler怎么做到的一个线程对应一个Looper,如何保证只有一个MessageQueue: Handler内部通过ThreadLocal来实现一个线程对应一个Looper,并保证只有一个MessageQueue。
-
ThreadLocal在Handler机制中的作用: ThreadLocal在Handler机制中用于存储每个线程对应的Looper对象。
-
IdleHandler及其使用场景: IdleHandler是一种回调接口,可以在消息队列空闲时执行特定操作,常用于在UI线程空闲时执行一些耗时操作。
-
消息屏障、同步屏障机制: 消息屏障是指通过发送特殊的同步消息来控制消息处理的顺序,同步屏障机制用于保证一组消息按照指定的顺序执行。
-
子线程能不能更新UI: 子线程不能直接更新UI,必须通过Handler或者其他线程间通信的方式在主线程中更新UI。
-
为什么Android系统不建议子线程访问UI: 因为Android中UI操作必须在主线程中进行,子线程直接操作UI可能导致UI线程安全问题。
-
Android中为什么主线程不会因为Looper.loop()里的死循环卡死: 主线程中Looper.loop()里的死循环会不断从消息队列中取出消息进行处理,不会导致主线程卡死。
-
Looper.quit/quitSafely的区别: quit方法会立即终止消息循环,quitSafely会等待消息处理完毕后再退出。
-
通过Handler如何实现线程的切换: 可以在Handler的构造函数中传入指定的Looper对象来实现线程的切换。
-
Handler如何与Looper关联: Handler的构造函数中需要传入一个Looper对象来与之关联。
-
Looper如何与Thread关联: Looper是通过ThreadLocal来与线程关联的。
-
Looper.loop()源码: Looper.loop()方法是一个无限循环,不断从消息队列中获取消息并分发处理。
-
MessageQueue的enqueueMessage()方法如何进行线程同步的: enqueueMessage()方法内部使用了锁来实现线程同步。
-
MessageQueue的next()方法内部原理: next()方法会阻塞等待消息到来,然后返回消息给Looper进行处理。
-
子线程中是否可以用MainLooper去创建Handler,Looper和Handler是否一定处于一个线程: 子线程中不能使用MainLooper创建Handler,Looper和Handler通常是处于同一个线程中。
-
ANR和Handler的联系: 如果在主线程中有耗时操作没有及时处理,会导致ANR,通过Handler可以将耗时操作放到子线程中执行,避免ANR的发生。