整体复习,多为整理,持续更新中...
(一)Handler 相关知识
1、Handler Looper MessageQueue Message 关系是什么?
Looper 负责的是创建一个 MessageQueue 对象, 然后进入到一个无限循环体中不断取出Message,而这些 Message都是由一个或者 多个 Handler 进行创建处理。
2、Messagequeue 的数据结构是什么?为什么要用这个数据结构?
Messagequeue是基础数据结构中“先进先出”的一种数据结构
-
解耦: 在项目启动之初来预测将来项目会碰到什么需求,是极其困难的。消息队列在处理过 程中间插入了一个隐含的、基于数据的接口层,两边的处理过程都要实现这一接口。 这允许你独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束
-
冗余: 有些情况下,处理数据的过程会失败。除非数据被持久化,否则将造成丢失。消息队 列把数据进行持久化直到它们已经被完全处理,通过这一方式规避了数据丢失风险。 在被许多消息队列所采用的”插入-获取-删除”范式中,在把一个消息从队列中删除之 前,需要你的处理过程明确的指出该消息已经被处理完毕,确保你的数据被安全的保 存直到你使用完毕。
-
扩展性: 因为消息队列解耦了你的处理过程,所以增大消息入队和处理的频率是很容易的;只 要另外增加处理过程即可。不需要改变代码、不需要调节参数。扩展就像调大电力按 钮一样简单。
-
灵活性 & 峰值处理能力: 在访问量剧增的情况下,应用仍然需要继续发挥作用,但是这样的突发流量并不常见; 如果为以能处理这类峰值访问为标准来投入资源随时待命无疑是巨大的浪费。使用消 息队列能够使关键组件顶住突发的访问压力,而不会因为突发的超负荷的请求而完全 崩溃。
-
可恢复性: 当体系的一部分组件失效,不会影响到整个系统。消息队列降低了进程间的耦合度, 所以即使一个处理消息的进程挂掉,加入队列中的消息仍然可以在系统恢复后被处 理。而这种允许重试或者延后处理请求的能力通常是造就一个略感不便的用户和一个 沮丧透顶的用户之间的区别。
-
送达保证: 消息队列提供的冗余机制保证了消息能被实际的处理,只要一个进程读取了该队列即 可。在此基础上,IronMQ 提供了一个”只送达一次”保证。无论有多少进程在从队列 中领取数据,每一个消息只能被处理一次。这之所以成为可能,是因为获取一个消息 只是”预定”了这个消息,暂时把它移出了队列。除非客户端明确的表示已经处理完了 这个消息,否则这个消息会被放回队列中去,在一段可配置的时间之后可再次被处理。
-
顺序保证:在大多使用场景下,数据处理的顺序都很重要。消息队列本来就是排序的,并且能保 证数据会按照特定的顺序来处理。IronMO 保证消息通过 FIFO(先进先出)的顺序 来处理,因此消息在队列中的位置就是从队列中检索他们的位置。
-
缓冲:在任何重要的系统中,都会有需要不同的处理时间的元素。例如,加载一张图片比应 用过滤器花费更少的时间。消息队列通过一个缓冲层来帮助任务最高效率的执行—写 入队列的处理会尽可能的快速,而不受从队列读的预备处理的约束。该缓冲有助于控 制和优化数据流经过系统的速度。
-
理解数据流:在一个分布式系统里,要得到一个关于用户操作会用多长时间及其原因的总体印象, 是个巨大的挑战。消息系列通过消息被处理的频率,来方便的辅助确定那些表现不佳 的处理过程或领域,这些地方的数据流都不够优化。
-
异步通信: 很多时候,你不想也不需要立即处理消息。消息队列提供了异步处理机制,允许你把 一个消息放入队列,但并不立即处理它。你想向队列中放入多少消息就放多少,然后 在你乐意的时候再去处理它们。
3、如何在子线程中创建 Handler?
创建步骤: 在子线程中创建 handler,要确保子线程有 Looper,UI 线程默认包含 Looper 我们需要用到一个特殊类 HandlerThread 这个类可以轻松的创建子线程 handler
- 创建一个 HandlerThread,即创建一个包含 Looper 的线程
HandlerThread handlerThread=new HandlerThread("xuan");
handlerThread.start();//创建 HandlerThread 后一定要记得 start();
- 通过 HandlerThread 的 getLooper 方法可以获取 Looper
Looper looper=handlerThread.getLooper();
- 通过 Looper 我们就可以创建子线程的 handler 了
Handlr handler=new Handler(looper);
- 通过该 handler 发送消息,就会在子线程执行;
提示:如果要 handlerThread 停止:handlerThread.quit();
完整代码:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//initHandle
HandlerThread hanlerThread = new HandlerThread("子线程");
hanlerThread.start();
final Handler handler = new Handler(hanlerThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.d("----->", "线程:" + Thread.currentThread().getName());
}
};
findViewById(R.id.handle).setOnClickListener(v -> {
handler.sendEmptyMessage(100);
});
}
}
4、Handler post 方法原理?
-
- 消息是通过 MessageQueen 中的 enqueueMessage()方法加入消息队列中的,并 且它在放入中就进行好排序,链表头的延迟时间小,尾部延迟时间最大
-
- Looper.loop()通过 MessageQueue 中的 next()去取消息
-
- next()中如果当前链表头部消息是延迟消息,则根据延迟时间进行消息队列会 阻塞,不返回给 Looper message,知道时间到了,返回给 message
-
- 如果在阻塞中有新的消息插入到链表头部则唤醒线程
-
- Looper 将新消息交给回调给 handler 中的 handleMessage 后,继续调用 MessageQueen 的 next()方法,如果刚刚的延迟消息还是时间未到,则计算时间 继续阻塞
总结: handler.postDelay() 的实现 是通过 MessageQueue 中执行时间顺序排列,消息队 列阻塞,和唤醒的方式结合实现的。 如果真的是通过延迟将消息放入到 MessageQueen 中,那放入多个延迟消息就要 维护多个定时器,
5、Android 消息机制的原理及源码解析
1.消息机制概述
1)消息机制的简介
在 Android 中使用消息机制,我们首先想到的就是 Handler。没错,Handler 是 Android 消息机制的上层接口。Handler 的使用过程很简单,通过它可以轻松地将 一个任务切换到 Handler 所在的线程中去执行。通常情况下,Handler 的使用场 景就是更新 UI。
如下就是使用消息机制的一个简单实例:
在子线程中,进行耗时操作,执行完操作后,发送消息,通知主线程更新 UI。 这便是消息机制的典型应用场景。我们通常只会接触到 Handler 和 Message 来完 成消息机制,其实内部还有两大助手来共同完成消息传递。
2)消息机制的模型
消息机制主要包含:MessageQueue,Handler和Looper这三大部分,以及Message。
下面我们一一介绍:
- Message:需要传递的消息,可以传递数据;
- MessageQueue:消息队列,但是它的内部实现并不是用的队列,实际上是通过 一个单链表的数据结构来维护消息列表,因为单链表在插入和删除上比较有优 势。主要功能向消息池投递消息(MessageQueue.enqueueMessage)和取走消息池 的消息(MessageQueue.next);
- Handler:消息辅助类,主要功能向消息池发送各种消息事件 (Handler.sendMessage)和处理相应消息事件(Handler.handleMessage);
- Looper:不断循环执行(Looper.loop),从 MessageQueue 中读取消息,按分发机 制将消息分发给目标处理者。
3)消息机制的架构
消息机制的运行流程:在子线程执行完耗时操作,当 Handler 发送消息时,将会 调用MessageQueue.enqueueMessage,向消息队列中添加消息。当通过Looper.loop 开启循环后,会不断地从线程池中读取消息,即调用 MessageQueue.next,然后 调用目标 Handler(即发送该消息的 Handler)的 dispatchMessage 方法传递消息, 然后返回到 Handler 所在线程,目标 Handler 收到消息,调用 handleMessage 方 法,接收消息,处理消息。
MessageQueue,Handler 和 Looper 三者之间的关系:每个线程中只能存在一个 Looper,Looper 是保存在 ThreadLocal 中的。主线程(UI 线程)已经创建了一 个 Looper,所以在主线程中不需要再创建 Looper,但是在其他线程中需要创建 Looper。每个线程中可以有多个 Handler,即一个 Looper 可以处理来自多个 Handler 的消息。 Looper 中维护一个 MessageQueue,来维护消息队列,消息队 列中的 Message 可以来自不同的 Handler。
2.消息机制的源码解析
3.总结
以上便是消息机制的原理,以及从源码角度来解析消息机制的运行过程。可以简 单地用下图来理解。
6、Handler 都没搞懂,拿什么去跳槽啊?
7、Android Handler 消息机制(解惑篇)
Android 中线程的分类
带有消息队列,用来执行循环性任务(例如主线程、android.os.HandlerThread)
有消息时就处理,没有消息时就睡眠
没有消息队列,用来执行一次性任务(例如 java.lang.Thread)
任务一旦执行完成便退出
带有消息队列线程概述
1. 四要素
Message(消息)→MessageQueue(消息队列)→Looper(消息循环)→Handler(消息发送和处理)2. 四要素的交互过程
具体工作过程→ 消息队列的创建→ 消息循环→ 消息的发送→ 最基本的两个 API→Handler.sendMessage→ 带一个 Message 参数,用来描述消息的内容→ Handler.post→
带一个 Runnable 参数,会被转换为一个 Message 参数→ 消息的处理
基于消息的异步任务接口
android.os.HandlerThread :适合用来处于不需要更新 UI 的后台任务
android.os.AyncTask :适合用来处于需要更新 UI 的后台任务
带有消息队列线程的具体实现
ThreadLocal :
ThreadLocal 并不是一个 Thread,而是 Thread 的局部变量。当使用 ThreadLocal 维护变量时,ThreadLocal
为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所 对
应的副本。 从线程的角度看,目标变量就象是线程的本地变量,这也是类名中“Local”所 要表达的意思。
Looper:
用于在指定线程中运行一个消息循环,一旦有新任务则执行,执行完继续等待下 一个任务,即变成 Looper 线程。
Looper 类的注释里有这样一个例子:
class LooperThread extends Thread{
public Handler mHandler;
@Override
public void run() {
super.run();
//将当前线程初始化为 Looper 线程
Looper.prepare();
// ...其他处理,如实例化 handler
mHandler = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
// process incoming messages here
}
};
// 开始循环处理消息队列
Looper.loop();
其实核心代码就两行,我们先来看下图 Looper.prepare()方法的具体实现
}
}
我们可以看出:
prepare()其核心就是将 looper 对象定义为 ThreadLocal 一个 Thread 只能有一个 Looper 对象 prepare()
方法会调用 Looper 的构造方法,初始化一个消息队列,并且 指定当前线程 在调用 Looper.loop()方法之前,确保已
经调用了 prepare(boolean quitAllowed)方法,并且我们可以调用 quite 方法结束循环
8、Android 消息机制
(二)Activity 相关
1、启动模式以及使用场景?
2、onNewIntent()和 onConfigurationChanged()
3、onSaveInstanceState()和 onRestoreInstanceState()
4、Activity 到底是如何启动的
(三)Fragment
1、Fragment 生命周期和 Activity 对比
2、Fragment 之间如何进行通信
3、Fragment 的 startActivityForResult
4、Fragment 重叠问题
(四)Service 相关
1、进程保活
2、Service 的运行线程(生命周期方法全部在主线程)
3、Service 启动方式以及如何停止
4、ServiceConnection 里面的回调方法运行在哪个线程?
(五)Android 布局优化之 ViewStub、 include、merge
1、什么情况下使用 ViewStub、include、merge?
2、他们的原理是什么?
(六)BroadcastReceiver 相关
1、注册方式,优先级
2、广播类型,区别
3、广播的使用场景,原理
(七)AsyncTask 相关
1、AsyncTask 是串行还是并行执行?
2、AsyncTask 随着安卓版本的变迁