[译]Android应用程序基础 >> 进程和线程(Processes and Threads)
当一个应用程序的第一个组件需要被运行时,android系统会启动一个只有一个主线程的linux进程来运行这个组件。默认情况下,应用程序的所有组件都是运行在这个主线程中的。
但是你也可以使组件运行在其它的进程中,而且你也可以从任何进程中新开起子线程。
进程
在manifest文件中的<activity>,<service>,<receiver>和<provider>标签都有一个名为process的属性,通过设置这个属性,我们可以控制这个组件运行在哪个进程中。我们可以让这个应用程序中的所有组件运行在各自不同的进程中,或者让它们中的一部分运行在同一个进程中,当然我们也可以指定不同程序的组件运行在同一个进程中――需要不同的应用程序共享相同的用户id和用相同的认证进行签名。<application>标签也有一个名为process的属性,它是用于设置本应用程序中所有组件默认运行的进程。
所有的组件都是运行在进程的主线程中,所以报告用户动作事件――比如View.onKeyDown()方法――都是运行在进程的主线程中的。这意味着组件不应该执行耗时操作(比如网络操作和大循环计算),因为这样会阻塞线程。你可以新开启一个子线程来做这种耗时的工作。
在某些时候,android系统会终止某个进程,比如当系统需要向用户提供更重要的服务,而系统的可用内存又比较少的情况。在这种情形下,运行在那个进程中的所有组件也会被清理掉。
在选择终止哪一个进程的时候,android会对评估进程对于用户的重要性。比如一个运行有可见的activity组件的进程的重要性就要比一个没有运行可见的activity组件的进程的重要性要高。进程的重要性取决于运行在这个进程中的组件的状态。
线程
虽然在默认情况下,应用程序的就运行在一个进程中,但你可以在需要的时候,新开启线程来完成耗时的后台工作。
和j2se中的一样,线程是用java.lang.Thread类型来表示的。Android中提供了一些用于管理线程的便利类――android.os.Looper类用于在线程中运行一个消息循环,android.os.Handler类用于处理消息,android.os.HandlerThread类用于创建一个具有消息循环的线程。
远程过程调用
Android系统有一个用于远程过程调用(RPCs)的轻量级机制――即一个方法在本地被调用,但是在远程(另一个进程)被执行,执行完成后生成的结果返回给调用者。这就需要将方法调用和调用的数据分解到一个操作系统可以理解的程度,然后将其从本地进程地址空间传输到远程进程地址空间,并且在远程重新装配并执行。执行生成的结果则进行反方向的传输。Android已经实现了底层的机制,所以开发者只需要集中精力于实现RPC接口即可。
一个RPC接口只可以有方法。默认情况下,所有的方法以同步模式执行(即在远程方法执行完成之前,无论是否有返回值,本地调用者都是处于阻塞状态)
简明地说,RPC以下面的流程来工作的:你需要声明一个RPC接口,此接口用于你后面用一个单独的IDL(接口定义语言)去实现。aidl工具会依据这个接口的声明来生成一个java语言版的接口声明,这个java接口声明对本地进程和远程进程都必须是可用的。它包含了两个内部类,如下图所示:
内部类已经有了用于管理你声明的RPC接口的远程过程调用的必需代码。两个内部类都实现了android.os.IBinder接口。其中一个内部类被操作系统内部在本地使用,所以你可以忽略它;另一个内部类,名字叫Stub,是从android.os.Binder类继承下来的,这里面除了用于执行IPC调用的内部代码之外,还包含了你在RPC接口中声明的接口方法,你应该继承这个Stub类来实现这在RPC接口中声明的方法,如上图所示。
通常情况下,远程进程是被一个service组件控制的(因为service组件可以告知系统这个进程以及连接到其它进程的连接)。
Typically, the remote process would be managed by a service (because a service can inform the system about the process and its connections to other processes). It would have both the interface file generated by the aidl tool and the Stub subclass implementing the RPC methods. Clients of the service would have only the interface file generated by the aidl tool.
一个service组件和其客户端建立连接的流程如下:
Service组件的客户端(本地)需要实现android.content.ServiceConnection.onServiceConnected()和android.content.ServiceConnection.onServiceDisconnected()方法,用以在成功连接到(和断开)远程的service组件时候获取通知。通过调用bindService()方法来建立连接。
重载Service组件的onBind()方法,并通过传递给onBind()方法的intent对象来决定接受或拒绝连接。若接受连接,则返回Stub子类的对象。一旦此Service组件接受了连接,Android系统就会在本地回调onServiceConnected()方法,并且将IBinder对象传入,service组件管理了一个此Stub子类的代理。本地的客户端可以通过这个代理来作用于远程端的service组件。