引言
当应用程序的组件第一次运行时,Android 将启动一个只有一个执行线程的 Linux 过程。默认,应用程序所有的组件运行在这个过程和线程中。然而,你能够安顿组件运行在其余过程中,且你能够为过程衍生出其它线程。本文从上面几点来介绍 Android 的过程与线程:
1、过程
2、线程
2.1、近程过程调用(Remote procedure calls,RPCs)
2.2、线程平安办法
1、过程
组件运行于哪个过程中由清单文件管制。组件元素——<activity>、<service>、<receiver>、<provider>,都有一个 process 属性能够指定组件运行在哪个过程中。这个属性能够设置为每个组件运行在本人的过程中,或者某些组件共享一个过程而其余的不共享。他们还能够设置为不同应用程序的组件运行在同一个过程中——假如这些应用程序共享同一个 Linux 用户 ID 且被调配了同样的权限。<application> 元素也有 process 属性,为所有的组件设置一个默认值。
所有的组件都在特定过程的主线程中实例化,且零碎调用组件是由主线程差遣。不会为每个实例创立独自的线程,因而,对应这些调用的办法——诸如 View.onKeyDown() 报告用用户的行为和生命周期告诉,总是运行在过程的主线程中。这意味着,没有组件当被零碎调用时应该执行很长时间或阻塞操作(如网络操作或循环计算),因为这将阻塞过程中的其它组件。你能够为长操作衍生独立的线程。
public boolean onKeyDown(int keyCode,KeyEvent event):默认实现 KeyEvent.Callback.onKeyMultiple(),当按下视图的 KEYCODE_DPAD_CENTER 或 KEYCODE_ENTER 而后开释时执行,如果视图可用且可点击。
参数
keyCode- 示意按钮被按下的键码,来自 KeyEvent
event- 定义了按钮动作的 KeyEvent 对象
返回值
如果你处理事件,返回 true;如果你想下一个接收者处理事件,返回 false。
当内存残余较小且其它过程申请较大内存并须要立刻调配,Android 要回收某些过程,过程中的应用程序组件会被销毁。当他们再次运行时,会从新开始一个过程。
当决定终结哪个过程时,Android 会衡量他们对用户重要性的绝对权值。例如,与运行在屏幕可见的流动过程相比(前台过程),它更容易敞开一个过程,它的流动在屏幕是不可见(后盾过程)。决定是否终结过程,取决于运行在过程中的组件状态。对于组件的状态,将在前面一篇——组件生命周期中介绍。
2、线程
尽管你可能会将你的应用程序限度在一个过程中,但有时候你会须要衍生一个线程做一些后盾工作。因为用户界面必须很快地响应用户的操作,所以流动寄宿的线程不应该做一些耗时的操作如网络下载。任何不可能在短时间实现的操作应该调配到别的线程。
线程在代码中是用规范的 Java 线程对象创立的,Android 提供了一些不便的类来治理线程——Looper 用于在线程中运行音讯循环、Handler 用户解决音讯、HandlerThread 用户设置一个音讯循环的线程。
Looper 类
该类用户在线程中运行音讯循环。线程默认没有音讯循环,能够在线程中调用 prepare() 创立一个运行循环;而后调用 loop() 解决音讯直到循环完结。大部分音讯循环交互是通过 Handler 类。上面是一个典型的执行一个 Looper 线程的例子,别离应用 prepare() 和 loop() 创立一个初始的 Handler 与 Looper 交互:
class LooperThread extends Thread {
public Handler mHandler;
public void run() {Looper.prepare();
mHandler = new Handler() {public void handleMessage(Message msg) {// process incoming messages here}
};
Looper.loop();}
}
更多的对于 Looper 的信息及 Handler、HandlerThread 请参阅相干材料。
2.1、近程过程调用(Remote procedure calls,RPCs)
Android 有一个轻量级的近程过程调用机制——办法在本地调用却在近程(另外一个过程中)执行,后果返回给调用者。这须要将办法调用和它随同的数据合成为操作系统可能了解的档次,从本地过程和地址空间传输到近程过程和地址空间,并从新组装调用。返回值以相同方向传输。Android 提供了做这些工作的所有代码,这样咱们能够专一于定义和执行 RPC 接口自身。
一个 RPC 接口仅蕴含办法。所有的办法同步地执行(本地办法阻塞直到近程办法执行实现),即便是没有返回值。简言之,该机制工作原理如下:首先,你用简略的 IDL(interface definition language,接口定义语言)申明一个你想实现的 RPC 接口。从这个申明中,aidl 工具生成一个 Java 接口定义,提供给本地和近程过程。它蕴含两个外部类,如下图所示:
外部类有治理你用 IDL 定义的接口的近程过程调用所须要的所有代码。这两个外部类都实现了 IBinder 接口。其中之一就是在本地由零碎外部应用,你写代码能够疏忽它。另外一个是 Stub,扩大自 Binder 类。除了用于无效地 IPC(interprocess communication)调用的外部代码,外部类在 RPC 接口申明中还蕴含办法申明。你能够定义 Stub 的子类实现这些办法,如图中所示。
通常状况下,近程过程有一个服务治理(因为服务能告诉零碎对于过程和它连贯的其它过程的信息)。它有由 aidl 工具生成的接口文件和 Stub 子类实现的 RPC 办法。服务的客户端仅有由 aidl 工具生成的接口文件。
上面介绍服务如何与它的客户端建设连贯:
服务的客户端(在本地端的)应该实现 onServiceConnected() 和 onServiceDisconnected() 办法,因而当与近程服务建设连贯胜利和断开连接是会告诉它。而后调用 bindService() 建设连贯。
服务的 onBind() 办法将实现为承受或回绝连贯,者取决于它承受到的用意(该用意传送到 binServive())。如果连贯被承受,它返回一个 Stub 子类的实例。
如果服务承受连贯,Android 调用客户端的 onServiceConnected() 办法且传递给它一个 IBinder 对象,返回由服务治理的 Stub 子类的一个代理。通过代理,客户端能够调用近程服务。
这里只是简略地形容,省略了一些 RPC 机制的细节。你能够查阅相干材料或持续关注 Android 开发之旅,前面将为你奉上。
2.2、线程平安办法
在一些状况下,你实现的办法可能会被不止一个线程调用,因而必须写成线程平安的。这对近程调用办法是正确的——如上一节探讨的 RPC 机制。当从 IBinder 过程中调用一个 IBinder 对象中实现的一个办法,这个办法在调用者的线程中执行。然而,当从别的过程中调用,办法将在 Android 保护的 IBinder 过程中的线程池中抉择一个执行,它不在过程的主线程中执行。例如,一个服务的 onBind() 办法在服务过程的主线程中被调用,在 onBind() 返回的对象中执行的办法(例如,实现 RPC 办法的 Stub 子类)将在线程池中被调用。因为服务能够有一个以上的客户端,所以同时能够有一个以上的线程在执行同一个 IBinder 办法。因而,IBinder 的办法必须是线程平安的。
同样,一个内容提供者能够承受其它过程产生的数据申请。尽管 ContentResolver 和 ContentProvider 类暗藏过程通信如何治理的,对应哪些申请的 ContentResolver 办法——query()、insert()、delete()、update()、getType(),在内容提供者的过程的线程池中被调用,而不是在这一过程的主线程中。因为这些办法能够同时从任意数量的线程中调用,他们也必须实现为线程平安的。
注:来自 51CTO 博客作者 Saylor87 的作品