先贴个图:
〇、进程和线程的区别
这里先看一下进程和线程的区别和关联:
进程是操作系统中最基本的资源分配单元。每个进程都有自己独立的内存空间,拥有自己的代码、数据、栈、堆等资源。进程之间是相互独立的,互不干扰。操作系统会负责进程的创建、切换和销毁等管理工作。
而线程是进程中更小的执行单元。一个进程可以包含多个线程,这些线程共享进程的资源,但又可以独立运行和调度。线程之间可以通过共享内存等方式进行通信和协作。
比如说,你打开一个文字编辑器,这就是一个进程。在这个进程里,可能有以下几个线程在工作:
- 主线程负责处理用户的输入和界面更新
- 另一个线程在后台自动保存文件
- 还有一个线程在实时拼写检查
这些线程共享编辑器进程的内存空间、文件系统等资源,但又可以独立运行,互不干扰。
线程的优势在于可以提高程序的并发性和响应性。因为线程切换的开销比进程小得多,所以多线程程序可以更好地利用CPU资源,提高整体的执行效率。
但同时,线程之间也需要小心协调,避免出现数据竞争、死锁等并发问题。这就需要操作系统提供合适的线程同步机制,如互斥锁、信号量等。
总之,进程提供了一个安全隔离的执行环境,线程则是在这个环境中执行具体任务的基本单元。两者相辅相成,共同构成了操作系统的进程管理机制。
一、Handler
1.1 Handler 定义
首先来看看官方文档:Handler
A Handler allows you to send and process
Message
and Runnable objects associated with a thread’sMessageQueue
. Each Handler instance is associated with a single thread and that thread’s message queue. When you create a new Handler it is bound to aLooper
. It will deliver messages and runnables to that Looper’s message queue and execute them on that Looper’s thread.
这是什么意思呢? 意思就是 Handler 可以发送以及处理 与线程的 MessageQueue 相关联的 Message 和 Runnable 对象。 每一个Handler实例都只能与一个线程(Thread) 和消息队列(MessageQueue) 相关联 。当我们创建一个新 Handler实例时他会绑定到 Looper
中。Handler 会将消息和可运行对象传递到与其绑定的 Looper 的消息队列,并在该 Looper 所在的线程上执行它们对应逻辑。
也就是说:
- 消息队列(Message Queue) 是计算机科学和系统设计中一种通信和数据传输机制。它作为一个临时存储和路由系统,用于在更大的软件架构中的不同组件、应用程序或系统之间交换消息
- Looper 是一个消息处理循环:它从 MessageQueue 中读取并处理消息项。通常情况下,Looper 与 HandlerThread(Thread 的子类)一起使用。
- Handler 是一个实用类,用于与 Looper 进行交互,主要通过将消息和可运行对象发布到线程的 MessageQueue 来实现。创建 Handler 时,它会绑定到特定的 Looper(以及关联的线程和消息队列)。
- 在典型的用法中,你会创建并启动一个 HandlerThread,然后通过其他线程创建一个或多个 Handler 对象,以便与 HandlerThread 实例进行交互。虽然创建 Handler 时必须在 HandlerThread 上运行,但一旦创建完成,就没有限制哪些线程可以使用 Handler 的调度方法(例如
post(Runnable)
)。 - Android 应用程序中的主线程(也称为 UI 线程)在创建应用程序实例之前被设置为处理程序线程。除了类文档外,这里有一个关于所有这些内容的不错的讨论
1.2 Handler的用途
这句话的意思是,Handler 允许你发送和处理与线程的 MessageQueue 相关联的 Message 和 Runnable 对象。具体来说,Handler 有两个主要用途:
- 调度消息和可运行对象:你可以使用 Handler 来安排在将来某个时间点执行的消息和可运行对象。
- 在不同线程上排队执行操作:你可以将一个操作排队到与你自己的线程不同的线程上,以便在后台执行。
举个例子,如果你需要在后台执行一些耗时的任务(例如网络请求、文件 I/O 或复杂的计算),你可以创建一个新的线程来执行这些任务。同时,你可以使用 Handler 来与主线程进行通信,以便在任务完成后更新用户界面或处理其他操作
通过以下方法可以实现消息的调度:
post(Runnable)
:将一个可运行对象(Runnable
)发布到与当前Handler
关联的线程的消息队列中。该可运行对象将在消息队列中的下一个空闲时刻执行。postAtTime(java.lang.Runnable, long)
:将可运行对象发布到指定的时间点执行。你可以指定一个绝对时间(以毫秒为单位)来安排执行。postDelayed(Runnable, Object, long)
:将可运行对象发布到指定的延迟时间后执行。你可以指定一个相对时间(以毫秒为单位)来安排执行。sendEmptyMessage(int)
:向消息队列发送一个空消息,不携带任何数据。接收方可以根据消息的标识符来处理它。sendMessage(Message)
:将一个自定义的Message
对象发布到消息队列中。Message
可以携带自定义的数据和标识符。sendMessageAtTime(Message, long)
:将Message
对象发布到指定的时间点执行。sendMessageDelayed(Message, long)
:将Message
对象发布到指定的延迟时间后执行。
这些方法允许你在 Android 应用程序中安排消息的执行,以便在合适的时间点执行任务、更新用户界面或处理其他操作。
post
系列的方法允许你将Runnable
对象入队,以便在消息队列接收到它时执行。sendMessage
系列的方法则允许你将一个携带数据的Message
对象入队,这个Message
对象会在Handler
的handleMessage(Message)
方法中被处理。
需要注意的是,使用 sendMessage
方法时,你需要实现一个 Handler
的子类,并重写 handleMessage(Message)
方法来处理这个消息。
总之,这些方法都是用来管理消息队列中的任务执行顺序,以及在不同线程之间传递消息和数据。
当我们向Handler
发布或发送一个任务时,你有两种选择。一种是让任务在消息队列准备好后立即处理,另一种是指定一个延迟时间或者一个绝对时间来处理任务。后两种方式可以让你实现超时、定时和其他基于时间的行为。这些都是Android中常见的任务调度和时间管理的方法。
- 立即处理任务:当你向Handler发布或发送一个任务时,如果你没有指定延迟时间或绝对时间,那么这个任务会在消息队列准备好后立即处理。你可以通过调用
post(Runnable)
或sendMessage(Message)
方法来实现这个功能。例如:
Handler handler = new Handler();
handler.post(new Runnable() {
@Override
public void run() {
// 这里是你的任务代码
}
});
- 指定延迟时间或绝对时间处理任务:如果你想让任务在一段时间后执行,或者在某个具体的时间点执行,你可以指定一个延迟时间或者一个绝对时间。这可以通过调用
postDelayed(Runnable, long)
或sendMessageDelayed(Message, long)
方法来实现。例如:
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
// 这里是你的任务代码
}
}, 2000); // 延迟2000毫秒后执行
这两种方式都是Android中常见的任务调度和时间管理的方法,可以帮助我们实现超时、定时和其他基于时间的行为。
当你的应用程序创建一个进程时,它的主线程专门用来运行一个消息队列,负责管理顶级应用对象(如活动、广播接收器等)以及它们创建的任何窗口。你可以创建自己的线程,并通过Handler
与主应用线程进行通信。这是通过在你的新线程中调用之前的post或sendMessage
方法来完成的。然后,给定的Runnable
或Message
将被安排在Handler
的消息队列中,并在适当的时候进行处理。这是Android中常见的线程和消息管理的方法。
1.3 概括
1. Nested classes(嵌套类)
在Android的Handler类中,Nested classes(嵌套类)是指在Handler类内部定义的类。这些嵌套类通常用于帮助Handler类完成其功能。例如,Handler类中有一个名为Callback
的接口,这个接口定义了一些方法,这些方法可以在Handler处理消息时被调用,以避免实现自己的子类。
然而,需要注意的是,Handler类本身并没有直接的Nested classes。但是,我们经常会在使用Handler时创建和使用嵌套类。例如,我们可能会创建一个Runnable的匿名内部类来定义要在Handler中执行的代码。这个Runnable就可以被看作是一个嵌套类。例如:
Handler handler = new Handler();
handler.post(new Runnable() {
@Override
public void run() {
// 这里是你的任务代码
}
});
在这个例子中,new Runnable() {...}
就是一个嵌套类,它被定义在Handler的上下文中,并且被用来定义一个任务,这个任务可以被Handler在适当的时候执行。
2. 公共构造函数
Handler()
: 已被弃用- Handler(Handler.Callback callback): 已被弃用
Handler(Looper looper)
: 使用提供的 Looper 而不是默认的。Handler(Looper looper, Handler.Callback callback)
: 使用提供的 Looper 而不是默认的,并采用回调接口来处理消息。
3. 公共方法
static Handler createAsync(Looper looper, Handler.Callback callback)
: 创建一个新的处理程序,其发布的消息和可运行对象不受同步障碍(例如显示垂直同步)的影响。static Handler createAsync(Looper looper)
: 创建一个新的处理程序,其发布的消息和可运行对象不受同步障碍(例如显示垂直同步)的影响。void dispatchMessage(Message msg)
: 在这里处理系统消息。分发消息
修饰符 返回值 | 方法名 |
---|---|
static Handler | createAsync(Looper looper, Handler.Callback callback) Create a new Handler whose posted messages and runnables are not subject to synchronization barriers such as display vsync. 创建一个新的处理程序,其发布的消息和可运行对象不受同步障碍(例如显示垂直同步)的影响。 |
static Handler | createAsync(Looper looper) Create a new Handler whose posted messages and runnables are not subject to synchronization barriers such as display vsync. 创建一个新的处理程序,其发布的消息和可运行对象不受同步障碍(例如显示垂直同步)的影响。 |
void | dispatchMessage(Message msg) Handle system messages here. 在这里处理系统消息。 |
final void | dump(Printer pw, String prefix) |
final Looper | getLooper() |
String | getMessageName(Message message) Returns a string representing the name of the specified message. 返回表示指定消息名称的字符串。 |
void | handleMessage(Message msg) Subclasses must implement this to receive messages. 子类必须实现它才能接收消息。 |
final boolean | hasCallbacks(Runnable r) Check if there are any pending posts of messages with callback r in the message queue. 检查消息队列中是否有任何带有回调 r 的待处理消息。 |
final boolean | hasMessages(int what) Check if there are any pending posts of messages with code ‘what’ in the message queue. 检查消息队列中是否有任何带有代码“what”的待处理消息。 |
final boolean | hasMessages(int what, Object object) Check if there are any pending posts of messages with code ‘what’ and whose obj is ‘object’ in the message queue. 检查消息队列中是否有任何代码为“what”、对象为“object”的待处理消息。 |
final Message | obtainMessage(int what, Object obj) Same as obtainMessage() , except that it also sets the what and obj members of the returned Message. 与 obtainMessage() 相同,只不过它还设置返回的 Message 的 What 和 obj 成员。 |
final Message | obtainMessage() Returns a new Message from the global message pool. 从全局消息池返回一个新的 Message 。 |
final Message | obtainMessage(int what, int arg1, int arg2) Same as obtainMessage() , except that it also sets the what, arg1 and arg2 members of the returned Message. 与 obtainMessage() 相同,只不过它还设置返回的 Message 的 What、arg1 和 arg2 成员。 |
final Message | obtainMessage(int what, int arg1, int arg2, Object obj) Same as obtainMessage() , except that it also sets the what, obj, arg1,and arg2 values on the returned Message. 与 obtainMessage() 相同,不同之处在于它还在返回的 Message 上设置 What、obj、arg1 和 arg2 值。 |
final Message | obtainMessage(int what) Same as obtainMessage() , except that it also sets the what member of the returned Message. 与 obtainMessage() 相同,只不过它还设置返回的 Message 的 What 成员。 |
final boolean | post(Runnable r) Causes the Runnable r to be added to the message queue. 导致 Runnable r 添加到消息队列中。 |
final boolean | postAtFrontOfQueue(Runnable r) Posts a message to an object that implements Runnable. 将消息发布到实现 Runnable 的对象。 |
final boolean | postAtTime(Runnable r, long uptimeMillis) Causes the Runnable r to be added to the message queue, to be run at a specific time given by uptimeMillis. 导致 Runnable r 添加到消息队列,并在 给定的特定时间运行。 |
final boolean | postAtTime(Runnable r, Object token, long uptimeMillis) Causes the Runnable r to be added to the message queue, to be run at a specific time given by uptimeMillis. 导致 Runnable r 添加到消息队列,并在 给定的特定时间运行。 |
final boolean | postDelayed(Runnable r, long delayMillis) Causes the Runnable r to be added to the message queue, to be run after the specified amount of time elapses. 导致 Runnable r 添加到消息队列,并在指定的时间过后运行。 |
final boolean | postDelayed(Runnable r, Object token, long delayMillis) Causes the Runnable r to be added to the message queue, to be run after the specified amount of time elapses. 导致 Runnable r 添加到消息队列,并在指定的时间过后运行。 |
final void | removeCallbacks(Runnable r) Remove any pending posts of Runnable r that are in the message queue. 删除消息队列中 Runnable r 的所有待处理帖子。 |
final void | removeCallbacks(Runnable r, Object token) Remove any pending posts of Runnable r with Object token that are in the message queue. 删除消息队列中任何待处理的 Runnable with Object 帖子。 |
final void | removeCallbacksAndMessages(Object token) Remove any pending posts of callbacks and sent messages whose obj is token. 删除任何待处理的回调帖子和发送的消息,其为 . |
final void | removeMessages(int what) Remove any pending posts of messages with code ‘what’ that are in the message queue. 删除消息队列中任何带有代码“what”的待处理消息帖子。 |
final void | removeMessages(int what, Object object) Remove any pending posts of messages with code ‘what’ and whose obj is ‘object’ that are in the message queue. 删除消息队列中所有代码为“what”、对象为“object”的待处理消息。 |
final boolean | sendEmptyMessage(int what) Sends a Message containing only the what value. 发送一条仅包含“what”值的消息。 |
final boolean | sendEmptyMessageAtTime(int what, long uptimeMillis) Sends a Message containing only the what value, to be delivered at a specific time. 发送一条仅包含“what”值的消息,该消息将在特定时间传递。 |
final boolean | sendEmptyMessageDelayed(int what, long delayMillis) Sends a Message containing only the what value, to be delivered after the specified amount of time elapses. 发送一条仅包含“what”值的消息,该消息将在指定的时间过后传送。 |
final boolean | sendMessage(Message msg) Pushes a message onto the end of the message queue after all pending messages before the current time. 将消息推送到消息队列的末尾,位于当前时间之前的所有待处理消息之后。 |
final boolean | sendMessageAtFrontOfQueue(Message msg) Enqueue a message at the front of the message queue, to be processed on the next iteration of the message loop. 将消息放入消息队列的前面,以便在消息循环的下一次迭代时进行处理。 |
boolean | sendMessageAtTime(Message msg, long uptimeMillis) Enqueue a message into the message queue after all pending messages before the absolute time (in milliseconds) uptimeMillis. 在绝对时间(以毫秒为单位)之前将消息排入所有待处理消息之后的消息队列中。 |
final boolean | sendMessageDelayed(Message msg, long delayMillis) Enqueue a message into the message queue after all pending messages before (current time + delayMillis). 将一条消息放入消息队列中,位于(当前时间+delayMillis)之前的所有待处理消息之后。 |
String | toString() Returns a string representation of the object. 返回对象的字符串表示形式。 |
4. 继承方法
继承自: java.lang.Object
修饰符 返回值 | 方法名 |
---|---|
Object | clone() Creates and returns a copy of this object. 创建并返回此对象的副本。 |
boolean | equals(Object obj) Indicates whether some other object is “equal to” this one. 指示其他对象是否“等于”此对象。 |
void | finalize() Called by the garbage collector on an object when garbage collection determines that there are no more references to the object. 当垃圾回收确定不再有对该对象的引用时,由垃圾回收器对对象调用。 |
final Class<?> | getClass() Returns the runtime class of this Object . 返回此 Object 的运行时类。 |
int | hashCode() Returns a hash code value for the object. 返回对象的哈希代码值。 |
final void | notify() Wakes up a single thread that is waiting on this object’s monitor. 唤醒正在等待此对象监视器的单个线程。 |
final void | notifyAll() Wakes up all threads that are waiting on this object’s monitor. 唤醒在此对象的监视器上等待的所有线程。 |
String | toString() Returns a string representation of the object. 返回对象的字符串表示形式。 |
final void | wait(long timeoutMillis, int nanos) Causes the current thread to wait until it is awakened, typically by being notified or interrupted, or until a certain amount of real time has elapsed. 使当前线程等待,直到它被唤醒,通常是通过通知或中断,或者直到经过一定数量的实时时间。 |
final void | wait(long timeoutMillis) Causes the current thread to wait until it is awakened, typically by being notified or interrupted, or until a certain amount of real time has elapsed. 使当前线程等待,直到它被唤醒,通常是通过通知或中断,或者直到经过一定数量的实时时间。 |
final void | wait() Causes the current thread to wait until it is awakened, typically by being notified or interrupted. 使当前线程等待,直到它被唤醒,通常是通过通知或中断。 |
5. 小结
为应用程序创建一个进程时,其主线程专用于运行消息队列,该消息队列负责管理顶层应用程序对象(activities,broadcast receivers 等)以及它们创建的窗口。我们可以创建自己的线程,然后通过 Handler 与主线程进行通信,方法是从新线程调用我们前面讲到的 postXXX 或 sendXXX 方法,传递的 Runnable 或 Message 将被加入 Handler 关联的消息队列中,并适时进行处理。
二、Looper
2.1 Looper定义
官方文档:Looper
Looper
: 用于运行线程的消息循环的类。默认情况下,线程没有与之关联的消息循环;若要创建一个循环, 需要在要运行循环的线程中调用 prepare()
,然后调用 loop()
使当前线程进入消息循环,让它处理消息,直到循环停止。
这句话是关于在Android中创建和使用HandlerThread
的。prepare()
和loop()
都是Looper
类的方法。这里是它们的基本用法:
- prepare():这个方法在当前线程中初始化一个新的消息循环。通常你不需要直接调用这个方法,因为它已经在
HandlerThread
的run()
方法中被调用了。 - loop():这个方法会使当前线程进入消息循环,直到
Looper
的quit()
或quitSafely()
方法被调用。在消息循环中,线程会一直等待新的消息,并在接收到消息后处理它。
下述代码是在Android开发中使用Looper线程的一种典型方式。通过分离prepare()
和loop()
的使用,我们可以在开始消息循环之前创建一个初始的Handler,从而使得我们可以与Looper进行通信。
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler(Looper.myLooper()) {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
2.2 概括
1. 公共方法
修饰符 返回值 | 方法名 |
---|---|
void | dump(Printer pw, String prefix) Dumps the state of the looper for debugging purposes. 转储活套的状态以进行调试。 |
static Looper | getMainLooper() Returns the application’s main looper, which lives in the main thread of the application. 返回应用程序的主循环器,该循环器位于应用程序的主线程中。 |
MessageQueue | getQueue() Gets this looper’s message queue. 获取此循环器的消息队列。 |
Thread | getThread() Gets the Thread associated with this Looper. 获取与此 Looper 关联的线程。 |
boolean | isCurrentThread() Returns true if the current thread is this looper’s thread. 如果当前线程是此循环器的线程,则返回 true。 |
static void | loop() Run the message queue in this thread. 在此线程中运行消息队列。 |
static Looper | myLooper() Return the Looper object associated with the current thread. 返回与当前线程关联的 Looper 对象。 |
static MessageQueue | myQueue() Return the MessageQueue object associated with the current thread. 返回与当前线程关联的 MessageQueue 对象。 |
static void | prepare() Initialize the current thread as a looper. 将当前线程初始化为循环器。 |
static void | prepareMainLooper() This method was deprecated in API level 30. The main looper for your application is created by the Android environment, so you should never need to call this function yourself. 此方法在 API 级别 30 中已弃用。应用程序的主循环器是由 Android 环境创建的,因此您永远不需要自己调用此函数。 |
void | quit() Quits the looper. 退出活套。 |
void | quitSafely() Quits the looper safely. 安全退出活套。 |
void | setMessageLogging(Printer printer) Control logging of messages as they are processed by this Looper. 控制此 Looper 处理消息时的日志记录。 |
String | toString() Returns a string representation of the object. 返回对象的字符串表示形式。 |
2. 继承方法
继承自 java.lang.Object
修饰符 返回值 | 方法名 |
---|---|
Object | clone() Creates and returns a copy of this object. 创建并返回此对象的副本。 |
boolean | equals(Object obj) Indicates whether some other object is “equal to” this one. 指示其他对象是否“等于”此对象。 |
void | finalize() Called by the garbage collector on an object when garbage collection determines that there are no more references to the object. 当垃圾回收确定不再有对该对象的引用时,由垃圾回收器对对象调用。 |
final Class<?> | getClass() Returns the runtime class of this Object . 返回此 Object 的运行时类。 |
int | hashCode() Returns a hash code value for the object. 返回对象的哈希代码值。 |
final void | notify() Wakes up a single thread that is waiting on this object’s monitor. 唤醒正在等待此对象监视器的单个线程。 |
final void | notifyAll() Wakes up all threads that are waiting on this object’s monitor. 唤醒在此对象的监视器上等待的所有线程。 |
String | toString() Returns a string representation of the object. 返回对象的字符串表示形式。 |
final void | wait(long timeoutMillis, int nanos) Causes the current thread to wait until it is awakened, typically by being notified or interrupted, or until a certain amount of real time has elapsed. 使当前线程等待,直到它被唤醒,通常是通过通知或中断,或者直到经过一定数量的实时时间。 |
final void | wait(long timeoutMillis) Causes the current thread to wait until it is awakened, typically by being notified or interrupted, or until a certain amount of real time has elapsed. 使当前线程等待,直到它被唤醒,通常是通过通知或中断,或者直到经过一定数量的实时时间。 |
final void | wait() Causes the current thread to wait until it is awakened, typically by being notified or interrupted. 使当前线程等待,直到它被唤醒,通常是通过通知或中断。 |
三、MessageQueue
3.1 MessageQueue的定义
官方文档: MessageQueue
在Android中,MessageQueue
是一个消息队列,它的作用是维护一个Message
的队列,供Looper
使用
简单来说,MessageQueue
是一个任务列表,这些任务(Messages
,Runnables
)将在某个特定线程中执行。Android系统有一个非常知名的主线程(UI线程)。你看到的方法只是将一个Runnable
添加到将在UI线程中执行的进程列表
MessageQueue
通过一个单链表(即mMessages
)来实现队列。由于Message
本身就有一个指向下一个Message
的Message
变量next
,所以MessageQueue
不需要借助其他结构来实现队列,只需要一个mMessages
变量指向链表的头节点就可以了。
总的来说,MessageQueue
是Android消息处理机制的重要组成部分,它与Looper
和Handler
一起,构成了Android的线程通信基础。
MessageQueue
是一个低级别的类,它维护了一个消息列表,这些消息将由Looper
进行分发。而这些消息并不是直接添加到MessageQueue
中的,而是通过与Looper
关联的Handler
对象添加的。
我们可以使用 Looper.myQueue()
检索当前线程的 MessageQueue。
3.2 概括
1. 嵌套类
Nested classes 嵌套类 | |
---|---|
interface | MessageQueue.IdleHandler Callback interface for discovering when a thread is going to block waiting for more messages. 回调接口,用于发现线程何时要阻塞等待更多消息。 |
interface | MessageQueue.OnFileDescriptorEventListener A listener which is invoked when file descriptor related events occur. 在发生文件描述符相关事件时调用的侦听器。 |
2. 公共方法
返回值 | 方法名 |
---|---|
void | addIdleHandler(MessageQueue.IdleHandler handler) Add a new IdleHandler to this message queue. 向此消息队列添加新 IdleHandler 消息。 |
void | addOnFileDescriptorEventListener(FileDescriptor fd, int events, MessageQueue.OnFileDescriptorEventListener listener) Adds a file descriptor listener to receive notification when file descriptor related events occur. 添加文件描述符侦听器,以便在发生文件描述符相关事件时接收通知。 |
boolean | isIdle() Returns true if the looper has no pending messages which are due to be processed. 如果 looper 没有待处理的消息,则返回 true。 |
void | removeIdleHandler(MessageQueue.IdleHandler handler) Remove an IdleHandler from the queue that was previously added with addIdleHandler(IdleHandler) . IdleHandler 从之前添加 的 addIdleHandler(IdleHandler) 队列中删除 。 |
void | removeOnFileDescriptorEventListener(FileDescriptor fd) Removes a file descriptor listener. 删除文件描述符侦听器。 |
3. 受保护的方法
Protected methods 受保护的方法 | |
---|---|
void | finalize() Called by the garbage collector on an object when garbage collection determines that there are no more references to the object. 当垃圾回收确定不再有对该对象的引用时,由垃圾回收器对对象调用。 |
4. 继承的方法
继承自: java.lang.Object
修饰符 返回值 | 方法名 |
---|---|
Object | clone() Creates and returns a copy of this object. 创建并返回此对象的副本。 |
boolean | equals(Object obj) Indicates whether some other object is “equal to” this one. 指示其他对象是否“等于”此对象。 |
void | finalize() Called by the garbage collector on an object when garbage collection determines that there are no more references to the object. 当垃圾回收确定不再有对该对象的引用时,由垃圾回收器对对象调用。 |
final Class<?> | getClass() Returns the runtime class of this Object . 返回此 Object 的运行时类。 |
int | hashCode() Returns a hash code value for the object. 返回对象的哈希代码值。 |
final void | notify() Wakes up a single thread that is waiting on this object’s monitor. 唤醒正在等待此对象监视器的单个线程。 |
final void | notifyAll() Wakes up all threads that are waiting on this object’s monitor. 唤醒在此对象的监视器上等待的所有线程。 |
String | toString() Returns a string representation of the object. 返回对象的字符串表示形式。 |
final void | wait(long timeoutMillis, int nanos) Causes the current thread to wait until it is awakened, typically by being notified or interrupted, or until a certain amount of real time has elapsed. 使当前线程等待,直到它被唤醒,通常是通过通知或中断,或者直到经过一定数量的实时时间。 |
final void | wait(long timeoutMillis) Causes the current thread to wait until it is awakened, typically by being notified or interrupted, or until a certain amount of real time has elapsed. 使当前线程等待,直到它被唤醒,通常是通过通知或中断,或者直到经过一定数量的实时时间。 |
final void | wait() Causes the current thread to wait until it is awakened, typically by being notified or interrupted. 使当前线程等待,直到它被唤醒,通常是通过通知或中断。 |
四、Message
4.1 Message的定义
官方文档: Message
在Android中,Message
是一个定义在android.os
包下的类,它是Android消息处理机制的核心组成部分。Message
充当着信息载体的角色,它包含了一些字段,用于传递和处理消息。
以下是Message
类的一些主要字段:
what
:用户自定义的消息代码,以便接收者可以识别这条消息是关于什么的。每个Handler
都有它自己的和消息代码对应的名称空间,因此你不用担心和其他的Handler
发生冲突。arg1
和arg2
:如果你只需要保存几个整数类型的值,相对于使用setData()
方法保存数据,使用arg1
和arg2
是低成本的替代品。obj
:一个发送给接收者的任意对象。当使用Messenger
跨进程发送消息时,如果obj
包含Parcelable
类,那么它只能是非空的。对于其他数据的传递,建议使用setData()
方法。replyTo
:可选的Messenger
用于当前消息发送后的回复。具体如何使用它的含义取决于发送方和接收方。
尽管Message
的构造函数是公开的,但是获取一个消息对象最好的方式是调用Message.obtain()
方法或者Handler.obtainMessage()
方法,它将从一个可回收对象池中获取Message
对象。
4.2 概括
1. 继承的常量
int | CONTENTS_FILE_DESCRIPTOR Descriptor bit used with describeContents() : indicates that the Parcelable object’s flattened representation includes a file descriptor. Parcelable 是Android中用于在内存中快速传递数据的一种接口,它的性能比Serializable 接口更优。在Parcelable 接口中,有一个方法叫做describeContents() ,这个方法返回一个整数,用于表示Parcelable 对象的特殊对象类型。当describeContents() 返回的值包含CONTENTS_FILE_DESCRIPTOR (这是一个常量,值为1)时,表示这个Parcelable 对象的扁平化表示(即,转化为可以在内存中传递的形式)包含文件描述符。文件描述符是一种可以代表打开的文件、套接字等的索引值,如果一个Parcelable 对象需要包含这样的文件描述符,那么在进行扁平化操作时,就需要特殊处理。 |
---|---|
int | PARCELABLE_WRITE_RETURN_VALUE Flag for use with writeToParcel(Parcel, int) : the object being written is a return value, that is the result of a function such as “Parcelable someFunction() “, “void someFunction(out Parcelable) “, or “void someFunction(inout Parcelable) “. writeToParcel(Parcel, int) 方法用于将Parcelable 对象写入到Parcel 对象中,以便在内存中传递。这个方法有两个参数,第一个参数是Parcel 对象,第二个参数是一个整数,用于提供关于如何写入对象的附加信息。当第二个参数包含PARCELABLE_WRITE_RETURN_VALUE 标志(这是一个常量,值为1)时,表示正在写入的对象是一个返回值,也就是说,这个对象是类似”Parcelable someFunction()”,“void someFunction(out Parcelable)”,或者”void someFunction(inout Parcelable)”这样的函数的结果。 |
2. 变量及属性
Fields | |
---|---|
public static final Creator<Message> | CREATOR |
public int | arg1 arg1 and arg2 are lower-cost alternatives to using setData() if you only need to store a few integer values. 在Message 类中,arg1 和arg2 是两个整型(int)字段,你可以直接使用它们来存储整数数据。而setData() 方法则是用来存储一个Bundle 对象,Bundle 对象可以包含各种类型的数据,但是创建和使用Bundle 对象会有一定的内存和性能开销。因此,如果你只需要存储几个整数值,使用arg1 和arg2 字段会是一个更低成本(即更高效、更节省内存)的选择,而不是使用setData() 方法。 |
public int | arg2 arg1 and arg2 are lower-cost alternatives to using setData() if you only need to store a few integer values. 同上 |
public Object | obj An arbitrary object to send to the recipient. 要发送给收件人的任意对象。 |
public Messenger | replyTo Optional Messenger where replies to this message can be sent. 可选的 Messenger,可在其中发送对此消息的回复。 |
public int | sendingUid Optional field indicating the uid that sent the message. 指示发送消息的 uid 的可选字段。 |
public int | what User-defined message code so that the recipient can identify what this message is about. 用户定义的消息代码,以便收件人可以识别此消息的内容。 |
3. 公共构造函数
Public constructors 公共构造函数 |
---|
Message() Constructor (but the preferred way to get a Message is to call Message.obtain() ). 构造函数(但获取 Message 的首选方法是调用 Message.obtain() )。 |
4. 公共方法
修饰符 返回值 | 方法名 |
---|---|
void | copyFrom(Message o) Make this message like o. 使此消息像 o 一样。 |
int | describeContents() Describe the kinds of special objects contained in this Parcelable instance’s marshaled representation. 描述此 Parcelable 实例的封送表示中包含的特殊对象的种类。 |
Runnable | getCallback() Retrieve callback object that will execute when this message is handled. 检索在处理此消息时将执行的回调对象。 |
Bundle | getData() Obtains a Bundle of arbitrary data associated with this event, lazily creating it if necessary. 获取与此事件关联的任意数据的 Bundle,并在必要时延迟创建它。 |
Handler | getTarget() Retrieve the Handler implementation that will receive this message. 检索将接收此消息的 Handler 实现。 |
long | getWhen() Return the targeted delivery time of this message, in milliseconds. 返回此消息的目标传递时间(以毫秒为单位)。 |
boolean | isAsynchronous() Returns true if the message is asynchronous, meaning that it is not subject to Looper synchronization barriers. 如果消息是异步的,则返回 true,这意味着它不受 Looper 同步障碍的约束。 |
static Message | obtain(Handler h) Same as obtain() , but sets the value for the target member on the Message returned. 与 obtain() 相同,但在返回的消息上设置目标成员的值。 |
static Message | obtain(Handler h, int what) Same as obtain() , but sets the values for both target and what members on the Message. 与 obtain() 相同,但设置消息上目标和成员的值。 |
static Message | obtain(Handler h, Runnable callback) Same as obtain(android.os.Handler) , but assigns a callback Runnable on the Message that is returned. 与 obtain(android.os.Handler) 相同,但在返回的消息上分配回调 Runnable。 |
static Message | obtain(Message orig) Same as obtain() , but copies the values of an existing message (including its target) into the new one. 与 obtain() 相同,但将现有消息(包括其目标)的值复制到新消息中。 |
static Message | obtain(Handler h, int what, int arg1, int arg2, Object obj) Same as obtain() , but sets the values of the target, what, arg1, arg2, and obj members. 与 obtain() 相同,但设置 target、what、arg1、arg2 和 obj 成员的值。 |
static Message | obtain(Handler h, int what, int arg1, int arg2) Same as obtain() , but sets the values of the target, what, arg1, and arg2 members. 与 obtain() 相同,但设置目标、what、arg1 和 arg2 成员的值。 |
static Message | obtain(Handler h, int what, Object obj) Same as obtain() , but sets the values of the target, what, and obj members. 与 obtain() 相同,但设置 target、what 和 obj 成员的值。 |
static Message | obtain() Return a new Message instance from the global pool. 从全局池中返回一个新的 Message 实例。 |
Bundle | peekData() Like getData(), but does not lazily create the Bundle. 与 getData() 类似,但不会延迟创建 Bundle。 |
void | recycle() Return a Message instance to the global pool. 将 Message 实例返回到全局池。 |
void | sendToTarget() Sends this Message to the Handler specified by getTarget() . 将此消息发送到 getTarget() 指定的处理程序。 |
void | setAsynchronous(boolean async) Sets whether the message is asynchronous, meaning that it is not subject to Looper synchronization barriers. 设置消息是否为异步消息,这意味着它不受 Looper 同步障碍的约束。 |
void | setData(Bundle data) Sets a Bundle of arbitrary data values. 设置任意数据值的 Bundle。 |
void | setTarget(Handler target) |
String | toString() Returns a string representation of the object. 返回对象的字符串表示形式。 |
void | writeToParcel(Parcel dest, int flags) Flatten this object in to a Parcel. 将此对象展平为 Parcel。 |
5. 继承的方法
- 继承自 java.lang.Object
Object
clone()
Creates and returns a copy of this object. 创建并返回此对象的副本。boolean
equals(Object obj)
Indicates whether some other object is “equal to” this one. 指示其他对象是否“等于”此对象。void
finalize()
Called by the garbage collector on an object when garbage collection determines that there are no more references to the object. 当垃圾回收确定不再有对该对象的引用时,由垃圾回收器对对象调用。final Class<?>
getClass()
Returns the runtime class of thisObject
. 返回此Object
的运行时类。int
hashCode()
Returns a hash code value for the object. 返回对象的哈希代码值。final void
notify()
Wakes up a single thread that is waiting on this object’s monitor. 唤醒正在等待此对象监视器的单个线程。final void
notifyAll()
Wakes up all threads that are waiting on this object’s monitor. 唤醒在此对象的监视器上等待的所有线程。String
toString()
Returns a string representation of the object. 返回对象的字符串表示形式。final void
wait(long timeoutMillis, int nanos)
Causes the current thread to wait until it is awakened, typically by being notified or interrupted, or until a certain amount of real time has elapsed. 使当前线程等待,直到它被唤醒,通常是通过通知或中断,或者直到经过一定数量的实时时间。final void
wait(long timeoutMillis)
Causes the current thread to wait until it is awakened, typically by being notified or interrupted, or until a certain amount of real time has elapsed. 使当前线程等待,直到它被唤醒,通常是通过通知或中断,或者直到经过一定数量的实时时间。final void
wait()
Causes the current thread to wait until it is awakened, typically by being notified or interrupted. 使当前线程等待,直到它被唤醒,通常是通过通知或中断。 - 继承自 接口 android.os.Parcelable
abstract int
describeContents()
Describe the kinds of special objects contained in this Parcelable instance’s marshaled representation. 描述此 Parcelable 实例的封送表示中包含的特殊对象的种类。abstract void
writeToParcel(Parcel dest, int flags)
Flatten this object in to a Parcel. 将此对象展平为 Parcel。
五、一些问题
5.1 Thread 与 Looper,Looper 与 MessageQueue,Handler 与 Looper 之间的数量对应关系是怎样的
Thread 与 Looper
答:线程默认没有消息循环,需要调用 Looper.prepare()
来达到目的。所以来看一下 Looper.prepare()
的源码
/** Initialize the current thread as a looper.
* This gives you a chance to create handlers that then reference
* this looper, before actually starting the loop. Be sure to call
* {@link #loop()} after calling this method, and end it by calling
* {@link #quit()}.
*/
public static void prepare() {
prepare(true);
}
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));
}
这里可以看到 有参 prepare()
方法是个单例模式设计思想的方法,Looper
类使用了ThreadLocal
来为每个线程创建一个唯一的Looper
实例。ThreadLocal
是一个线程局部变量,它为每个线程都提供了一个独立的变量副本,每个线程都只能访问自己的副本变量。
prepare(boolean quitAllowed)
方法首先检查当前线程是否已经有一个Looper
实例(通过sThreadLocal.get()
获取)。如果已经存在,那么抛出RuntimeException
异常,因为每个线程只能有一个Looper
实例。如果不存在,那么就创建一个新的Looper
实例,并将其设置到sThreadLocal
中(通过sThreadLocal.set(new Looper(quitAllowed))
)。
可以从这个方法中得到两个信息:
- 一个线程里调多次
Looper.prepare()
方法会抛出异常提示Only one Looper may be created per thread
,即一个线程只能创建一个Looper
。 prepare()
主要干的就是sThreadLocal.set(new Looper(quitAllowed));
这样就不难发现 调用多次 Looper.prepare()
并不会关联多个 Looper
,还会抛出异常。那直接new Looper
再关联上去呢? 其实这样也不行,因为 Looper
的构造方法是私有的:
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
在概览整个 Looper
的所有公开方法后,发现只有 prepare
和 prepareMainLooper
是做线程与 Looper
关联的工作的,而 prepareMainLooper
是 Android
环境调用的,不是用来给应用主动调用的。所以从 Looper
源码里掌握的信息来看,想给一个线程关联多个 Looper
的路不通。
另外我们从源码里能观察到,Looper
有一个 final
的 mThread
成员,在构造 Looper
对象的时候赋值为 Thread.currentThread()
,源码里再无可以修改 mThread
值的地方,所以可知 Looper
只能关联到一个线程,且关联之后不能改变。
说了这么多,还记得 Looper.prepare()
里干的主要事情是 sThreadLocal.set(new Looper(quitAllowed))
吗?与之对应的,获取本线程关联的 Looper
对象是使用静态方法 Looper.myLooper()
:
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
Looper 与 MessageQueue
源码:
public final class Looper {
/*
* API Implementation Note:
*
* This class contains the code required to set up and manage an event loop
* based on MessageQueue. APIs that affect the state of the queue should be
* defined on MessageQueue or Handler rather than on Looper itself. For example,
* idle handlers and sync barriers are defined on the queue whereas preparing the
* thread, looping, and quitting are defined on the looper.
*/
private static final String TAG = "Looper";
...
@UnsupportedAppUsage
final MessageQueue mQueue;
...
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
...
}
Looper
对象里有一个 MessageQueue
类型成员,在构造的时候 new
出的,并且它是一个 final
,没有地方能修改它的指向。
所以 Looper
和MessageQueue
是一一对应关系
Handler 与 Looper
同样先来看源码:
public class Handler {
final Looper mLooper;
final MessageQueue mQueue;
...
@Deprecated
public Handler() {
this(null, false);
}
/**
*...
*/
@Deprecated
public Handler(@Nullable Callback callback) {
this(callback, false);
}
/**
* ...
*/
public Handler(@NonNull Looper looper) {
this(looper, null, false);
}
/**
* ...
*/
public Handler(@NonNull Looper looper, @Nullable Callback callback) {
this(looper, callback, false);
}
/**
* ...
*
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public Handler(boolean async) {
this(null, async);
}
/**
* ...
*
* @hide
*/
public Handler(@Nullable Callback callback, boolean async) {
...
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;
...
}
/**
* ...
*
* @hide
*/
@UnsupportedAppUsage
public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
this(looper, callback, async, /* shared= */ false);
}
/** @hide */
public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async,
boolean shared) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
mIsShared = shared;
}
}
重点要看的就是 Handler(@Nullable Callback callback, boolean async)
和 Handler(Looper looper, Callback callback, boolean async)
这两个方法
Handler
对象里有 final Looper
成员,所以说 一个 Handler
只会对应一个固定的 Looper
对象。 构造 Handler
对象的时候如果不传 Looper
参数,会默认使用当前线程关联的 Looper
,如果当前线程没有关联 Looper
,会抛出异常。
其实 Handler
和 Looper
是多对一的关系,也就是说我们可以绑定多个 Handler
到同一个 Looper
。写个demo验证一下:
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
private Handler mHandler1;
private Handler mHandler2;
private Handler.Callback mCallback = new Handler.Callback() {
@Override
public boolean handleMessage(@NonNull Message msg) {
Log.d(TAG, "handleMessage: msg: " + msg.what);
return false;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHandler1 = new Handler(mCallback);
mHandler2 = new Handler(mCallback);
mHandler1.sendEmptyMessage(1);
mHandler2.sendEmptyMessage(2);
}
}
这里将两个Handler
都绑定到主线程的 Looper
当中,运行程序查看打印信息:
发现 msg1
和 msg2
可以依次输出。
小结: Handler 与 Looper 是多对一的关系,创建 Handler 实例时要么提供一个 Looper 实例,要么使用当前线程有关联的 Looper。
6.2 如果 Looper 能对应多个 Handler,那通过不同的 Handler 发送的 Message,那处理的时候代码是如何知道该分发到哪一个 Handler 的 handlerMessage 方法的
答:
在 Android 中,每个 Handler
实例都与创建它的线程的 Looper
关联。当你通过 Handler
发送 Message
或 Runnable
时,它们会被添加到 Looper
的消息队列中。然后,Looper
会按照它们在队列中的顺序来处理这些消息。
每个 Message
都包含一个对 Handler
的引用,这个 Handler
就是发送该 Message
的 Handler
。因此,当 Looper
从消息队列中取出 Message
来处理时,它会调用该 Message
所关联的 Handler
的 handleMessage
方法。
这就是 Looper
如何知道应该将 Message
分发到哪个 Handler
的 handleMessage
方法的。这个过程是在 Looper
的内部自动完成的,你不需要手动进行分发。
比如:
Handler handler1 = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
// 处理来自 handler1 的消息
}
};
Handler handler2 = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
// 处理来自 handler2 的消息
}
};
// 通过 handler1 发送消息
handler1.sendEmptyMessage(1);
// 通过 handler2 发送消息
handler2.sendEmptyMessage(2);
在这个示例中,handler1
发送的消息会被 handler1
的 handleMessage
方法处理,handler2
发送的消息会被 handler2
的 handleMessage
方法处理。这是由 Looper
自动完成的。
6.3 Handler 能用于线程切换的原理是什么
答:
在 Android 中,Handler
是一个非常重要的组件,它可以用于在不同的线程之间传递和处理消息。Handler
的工作原理是基于 Android 的消息队列(MessageQueue
)和循环器(Looper
)机制的。
以下是 Handler
用于线程切换的基本原理:
- 创建 Handler:当你在某个线程(通常是主线程)中创建一个
Handler
实例时,这个Handler
就会与该线程的Looper
对象关联起来。如果该线程没有Looper
,则需要先调用Looper.prepare()
方法来创建一个。 - 发送消息:当你想要将一个任务从当前线程切换到
Handler
所在的线程时,你可以通过Handler
的post()
或sendMessage()
方法将一个Runnable
或Message
对象发送到Handler
所关联的Looper
的消息队列中。 - 处理消息:
Looper
会不断地从其消息队列中取出并处理消息。当Looper
取出一个Message
时,它会调用该Message
所关联的Handler
的handleMessage()
方法来处理这个Message
。如果Message
是一个Runnable
,则Looper
会直接运行这个Runnable
。
通过这种方式,Handler
可以将任务从一个线程切换到另一个线程。这在 Android 开发中非常常见,例如,当你需要将一个耗时的任务切换到后台线程,或者当你需要将一个任务切换回主线程以更新 UI 时。
这就是 Handler
能用于线程切换的原理。
6.4 Runnable 对象也是被添加到 MessageQueue 里吗
答:
是的,Runnable
对象确实是被添加到 MessageQueue
中的。当你通过 Handler
的 post(Runnable)
方法发送一个 Runnable
时,这个 Runnable
会被封装成一个 Message
对象,然后这个 Message
对象会被添加到 Handler
所关联的 Looper
的 MessageQueue
中。
当 Looper
从 MessageQueue
中取出这个 Message
时,它会检查这个 Message
是否包含一个 Runnable
。如果包含,Looper
就会运行这个 Runnable
。
这就是 Runnable
对象被添加到 MessageQueue
并最终被执行的过程。
6.5 可以在 A 线程创建 Handler 关联到 B 线程及其消息循环吗
答:
创建 Handler
时会关联到一个 Looper
,而 Looper
是与线程一一绑定的,所以理论上讲,如果能得到要关联的线程的 Looper
实例,这是可以实现的。
public final class Looper {
@UnsupportedAppUsage
private static Looper sMainLooper; // guarded by Looper.class
/** Initialize the current thread as a looper.
* This gives you a chance to create handlers that then reference
* this looper, before actually starting the loop. Be sure to call
* {@link #loop()} after calling this method, and end it by calling
* {@link #quit()}.
*/
public static void prepare() {
prepare(true);
}
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));
}
/**
* Initialize the current thread as a looper, marking it as an
* application's main looper. See also: {@link #prepare()}
*
* @deprecated The main looper for your application is created by the Android environment,
* so you should never need to call this function yourself.
*/
@Deprecated
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
/**
* Returns the application's main looper, which lives in the main thread of the application.
*/
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
}
比如这里就是Looper
源码中获取 主线程 Looper
的相关方法。
平时写代码过程中,如果要从子线程向主线程添加一段执行逻辑,也经常这么干,这是可行的:
Handler mHandler = new Handler(Looper.getMainLooper());
mHandler.sendMessage(new Message().what = 1);
// or
mHandler.post(() -> {
// todo list
});
那从子线程创建关联到其它子线程的 Looper 是否可行?可以写个demo验证一下
new Thread() {
@Override
public void run() {
setName("thread-one");
Looper.prepare();
final Looper threadLooper = Looper.myLooper();
new Thread() {
@Override
public void run() {
setName("thread-two");
try {
assert threadLooper != null;
Handler mHandler = new Handler(threadLooper);
mHandler.post(() -> {
Log.d(TAG, "run: " + Thread.currentThread().getName());
});
} catch (AssertionError e) {
throw new RuntimeException("threadLooper is null");
}
}
}.start();
Looper.loop();
}
}.start();
运行程序查看打印信息:
6.6 如何退出消息循环
答:
在Android中,消息循环是由Looper
类处理的。如果你想要退出消息循环,你可以调用Looper
的quit()
或quitSafely()
方法。这两个方法都会停止消息循环,但是quitSafely()
方法会处理完消息队列中的所有剩余消息,然后再退出。
这是一个简单的示例:
Looper looper = Looper.myLooper();
if (looper != null) {
looper.quitSafely();
}
请注意,这只会停止当前线程的Looper
。如果你在主线程中调用这个方法,可能会导致应用崩溃,因为主线程的Looper
负责处理所有的用户界面操作。因此,你应该避免在主线程中停止Looper
。在工作线程中使用Looper
时,你可以在适当的时候调用quit()
或quitSafely()
来停止消息循环。
6.7 消息可以插队吗
答:
是的,在Android中,你可以使用Handler
的postAtFrontOfQueue(Runnable r)
方法将消息插入到消息队列的前面。这样,这个消息会优先于其他消息被处理。这是一个简单的示例:
Handler handler = new Handler(Looper.getMainLooper());
handler.postAtFrontOfQueue(new Runnable() {
@Override
public void run() {
// 你的代码
}
});
在这个示例中,Runnable
对象被插入到主线程的消息队列的前面。当Looper
开始下一次循环时,它会优先处理这个Runnable
。
但是,请注意,频繁地使用postAtFrontOfQueue()
可能会导致消息队列中的其他消息被延迟处理,这可能会影响到应用的性能。因此,除非有特殊的需求,否则通常不建议使用这个方法。
6.8 消息可以撤回吗
答:
是的,你可以撤回已经发送到消息队列中但还未处理的消息。在Android中,Handler
类提供了几个方法来撤回消息:
removeCallbacks(Runnable r)
: 移除所有使用post(Runnable)
、postAtTime(Runnable, long)
和postDelayed(Runnable, long)
发送的还未处理的Runnable
对象。removeMessages(int what)
: 移除所有what
值匹配的还未处理的Message
对象。removeCallbacksAndMessages(Object token)
: 如果token
为null,移除所有的回调和消息。如果token
不为null,只移除token
值匹配的回调和消息。
这是一个简单的示例:
Handler handler = new Handler(Looper.getMainLooper());
Runnable runnable = new Runnable() {
@Override
public void run() {
// 你的代码
}
};
// 将Runnable对象发送到消息队列
handler.postDelayed(runnable, 10000); // 延迟10秒执行
// 在Runnable对象执行前撤回
handler.removeCallbacks(runnable);
在这个示例中,Runnable
对象被安排在10秒后执行。然后,我们立即调用removeCallbacks()
方法来撤回这个Runnable
对象,所以这个Runnable
对象的run()
方法将不会被执行。
6.9 应用程序的主线程是运行一个消息循环,在代码里是如何反映的
在Android应用程序中,主线程(也被称为UI线程)的消息循环是在应用程序启动时自动创建的。这是通过ActivityThread
类的main()
方法实现的。ActivityThread
是Android应用程序的入口点。
在main()
方法中,首先会为主线程创建一个Looper
对象,然后启动消息循环。以下是相关代码的简化版本:
public static void main(String[] args) {
// 为主线程准备Looper
Looper.prepareMainLooper();
// 创建ActivityThread对象
ActivityThread thread = new ActivityThread();
// 调用ActivityThread的attach方法
thread.attach(false);
// 开始消息循环
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
在这段代码中,Looper.prepareMainLooper()
方法会为主线程创建一个Looper
对象,Looper.loop()
方法则会启动消息循环。
请注意,不能在你的应用代码中直接调用这些方法。Android系统会在应用程序启动时自动为你做这些事情。