/**
* Perform a generic operation with the object.
*
* @param code The action to perform. This should
* be a number between {@link #FIRST_CALL_TRANSACTION} and
* {@link #LAST_CALL_TRANSACTION}.
* @param data Marshalled data to send to the target. Must not be null.
* If you are not sending any data, you must create an empty Parcel
* that is given here.
* @param reply Marshalled data to be received from the target. May be
* null if you are not interested in the return value.
* @param flags Additional operation flags. Either 0 for a normal
* RPC, or {@link #FLAG_ONEWAY} for a one-way RPC.
*/
public boolean transact(int code, Parcel data, Parcel reply, int flags)throws RemoteException;
IPC
IPC(Inter-Process-Communication) 进程间通信。
当我们在启动一个app时,Zygote会申请一个进程,app便会运行在这个进程中。在Android的,每一个app默认会运行在一个进程中,有自己独立的VM。
进程内通信
举一个例子,当Activity和 Service之间的通信,可以声明一个接口, 如IFeedback, 它只有一个方法onFeedback(data), 在Activity中有一个内部类实现了这个接口,然后把这个接口 set到Service中,这样当service中有状态变化需要传到Activity时,通过回调这个接口的onFeedback将数据传回到Activity。当然还可以通过发广播的机制。
为什么一个App有多进程
ContentProvider
去查询数据。如何开启多进程
在Android中使用多进程只有一种方式,那就是在四大组件中配置
android:process
属性。 配置进程的两种方式:1.采用
:
这种方式,如如果应用的包名是
com.fred.repository
, 后面运行的进程将会是com.fred.repository:remote
。:
这种形式会在当前进程前面加上包名。2.直接写完整的进程名, 如:
如果应用的包名是
com.fred.repository
, 后面运行的进程将会是com.fred.repository.remote
。采用
:
开头的进程属于当前应用的私有进程,其它应用的组件不可以和它跑在同一个进程中。第二种方式指定的进程是属于全局进程,其它应用通过shareUserId
方式可以和它跑在同一个进程中由此带来的问题
Android系统对每一个进程分配有不同的虚拟机,因此在多进程模式下一不留神就会带来一些数据上的问题。由于不在同一个进程中,线程同步机制也就无用了,SharedPreferences的可靠性下降,Application会多次创建。
基础
Android 框架的IPC沟通依赖单一的
IBinder
接口,Client端调用IBinder
接口的transact
函数,通过IPC机制而调用到服务端(Remote)的onTransact
函数 看一下IBinder:Android 中有两个实现类,因为跨进程,故两边一边一个。分别是
Binder
和BinderProxy
, 这两个类都存在于Binder.java
中。Binder
对应的是Service,BindProxy
对应的是客户端。Binder
类中的transact
中会调用onTransact
,execTransact
也会去调用onTransact
。transact
是给java来调用的,execTransact
让 c/c++本地来调用。onTransact
是一个抽象函数,让子类来覆写。init
是Java到 c/c++的沟通BinderProxy
中的init
也是Java到c/c++的沟通。IPC通信的通信三个步骤:
IBinder
接口的transact
函数,透过底层的Binder Driver驱动而间接调用到Binder基类的execTransact函数,从而调用到具体类的onTransact
, 看下面的例子采用Binder进行跨进程通信
采用Binder + Proxy/Stub模式实现跨进程通信
对于每一次的跨进程调用,我们都需要在客户端调用binder的
transact
方法,然后通过拦截服务端的onTransact
来进行处理。当前的例子比较简单,只有play
和stop
两种形为,如果客户端有较多的行为,我们就需要在onTransact
中对参数做很多的判断。再来看如何利用Proxy/Stub
模式来简化解决这个问题。采用AIDL进行通信的例子
AIDL的目的是定义Proxy/Stub来封装IBinder接口,以便开发者更方便的使用。IBinder接口中只有
transact
来进行ipc通信,不方便实际开发。[Proxy对应的是客户端,Stub 是服务端]用一个例子来说明IPC通信。假设有这么一个需求,在我们的App中会调用到外部设备的一个功能,这个设备采用的也是Android系统,设备有一个红外扫描的功能。当我们调用这个功能,会让扫描功能运行在一个独立的进程中,扫描成功后将数据传递给某个Activity。
Device.java
总结一下 采用AIDL进行通信的流程:
onBind
方法中返回这个类的对象使用Bundle进行跨进程的通信
这个其实很好理解,Bundle是传递数据的通道,当我们在App中需要集成QQ,微信的功能时,我们通常会发一个intent, 将我们业务相关的数据利用Bundle封装起来存放到intent中, 然后再启动了QQ或微信的某个Activity, 这便是一种很典型的利用
Bundle
进行跨进程通信的例子。采用Messager进行跨进程通信
采用
Messager
进行跨进程通信,其底层其实还是采用AIDL
, 关键地方已在代码中加上注释总结一下
Messenger
类包装IBinder接口机制,让其能跨进程的将Message
对象传递到另一个进程中。由于
Messenger
类实现了Parcelable
接口,所以Messenger
类可以透过IBinder
接口将Message对象传送到另一个进程的MessengerImpl
类。然后MessagerImpl通过Handler将Message对象丢入主线程的MQ里,让主线程来处理。 采用Messenger
这种机制不用考虑多线程同时执行Service的情况,因为这个时候多个Client(如Acivity1, Activity2)送来的Message对象都存入单一线程的MessageQueue中,由该线程依次逐一处理各Client传进来的Message对象Demo中的说明:
TestMessengerActivity
通过Android框架去取得MessengerService
对象,然后拿到了MessengerService
所在进程中的IBinder
接口,那么MessengerService
又如何取得TestMessengerActivity
中的IBinder
接口?答案是:TestMessengerActivity
先将IBinder接口中打包到Messager
对象中,随着Message被送到MessengerService
,MessengerService
接到传递过来的IBinder
接口时,会生成一个新的Messenger
对象,并拿到该IBinder
接口AIDL中的一些难点
暂放
使用Socket进行跨进程通信
原理:在Service中会创建一个
ServerSocket
来监听客户端连接,这个Service运行在一个单独的进程中,在客户端(如Activity)中会创建一个Socket
,让两者进行通信,用来交换数据。