详解Android进程和线程

2019-12-10 17:56:15王振洲

现在 UI 是安全的,代码也得到简化,因为任务分解成了两部分:一部分应在工作线程内完成,另一部分应在 UI 线程内完成。

下面简要概述了 AsyncTask 的工作方法,但要全面了解如何使用此类,您应阅读 AsyncTask 参考文档:

可以使用泛型指定参数类型、进度值和任务最终值
方法 doInBackground() 会在工作线程上自动执行
onPreExecute()、onPostExecute() 和 onProgressUpdate() 均在 UI 线程中调用
doInBackground() 返回的值将发送到 onPostExecute()
您可以随时在 doInBackground() 中调用publishProgress(),以在 UI 线程中执行 onProgressUpdate()
您可以随时取消任何线程中的任务

注意:使用工作线程时可能会遇到另一个问题,即:运行时配置变更(例如,用户更改了屏幕方向)导致 Activity 意外重启,这可能会销毁工作线程。 要了解如何在这种重启情况下坚持执行任务,以及如何在 Activity 被销毁时正确地取消任务,请参阅书架示例应用的源代码。

线程安全方法

在某些情况下,您实现的方法可能会从多个线程调用,因此编写这些方法时必须确保其满足线程安全的要求。

这一点主要适用于可以远程调用的方法,如绑定服务中的方法。如果对 IBinder 中所实现方法的调用源自运行 IBinder 的同一进程,则该方法在调用方的线程中执行。但是,如果调用源自其他进程,则该方法将在从线程池选择的某个线程中执行(而不是在进程的 UI 线程中执行),线程池由系统在与 IBinder 相同的进程中维护。例如,即使服务的 onBind() 方法将从服务进程的 UI 线程调用,在 onBind() 返回的对象中实现的方法(例如,实现 RPC 方法的子类)仍会从线程池中的线程调用。由于一个服务可以有多个客户端,因此可能会有多个池线程在同一时间使用同一 IBinder 方法。因此,IBinder 方法必须实现为线程安全方法。

同样,内容提供程序也可接收来自其他进程的数据请求。尽管 ContentResolver 和 ContentProvider 类隐藏了如何管理进程间通信的细节,但响应这些请求的 ContentProvider 方法(query()、insert()、delete()、update() 和 getType() 方法)将从内容提供程序所在进程的线程池中调用,而不是从进程的 UI 线程调用。由于这些方法可能会同时从任意数量的线程调用,因此它们也必须实现为线程安全方法。

进程间通信

Android 利用远程过程调用 (RPC) 提供了一种进程间通信 (IPC) 机制,通过这种机制,由 Activity 或其他应用组件调用的方法将(在其他进程中)远程执行,而所有结果将返回给调用方。这就要求把方法调用及其数据分解至操作系统可以识别的程度,并将其从本地进程和地址空间传输至远程进程和地址空间,然后在远程进程中重新组装并执行该调用。 然后,返回值将沿相反方向传输回来。 Android 提供了执行这些 IPC 事务所需的全部代码,因此您只需集中精力定义和实现 RPC 编程接口即可。