这些读书笔记是根据《Android开发艺术探索》和《Android群英传》这两本书,然后将书上的一些知识点做一下记录。方便学习和理解,如果有存在侵犯版权的地方,还麻烦告知。个人强烈建议购买这两本书。真心不错。
本节是和《Android开发艺术探索》中的第2章 “IPC机制” 有关系,建议先买书查看这一章。
()使用Messenger
Messenger通过在不同进程中传递Message对象,在Message中放入需要传递的数据,来实现进程间通信。Messenger是一种轻量级的IPC方案,它的底层实现是AIDL(通过Messenger的构造方法看出AIDL的痕迹)。Messenger一次处理一个请求,因此在服务端不用考虑线程同步问题,这是因为服务端中不存在并发执行的情况。
//Messenger的构造方法
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
//Messenger的构造方法
public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target);
}
使用Messenger的方法分为服务端和客户端
服务端:创建一个Service来处理客户端的连接请求,同时创建Handler并通过它来创建一个Messenger对象,然后在Service的onBind()中返回这个Messenger对象底层的Binder对象。
客户端:首先绑定服务端的Service,绑定成功后用服务端返回的IBinder对象创建Messenger,通过这个Messenger就可以向服务端发生消息。消息类型为Message对象,如果需要服务端发送消息给客户端,就需要创建一个Handler并创建一个新的Messenger,并把这个Messenger对象通过Message的replyTo参数传递给服务端,服务端通过这个replyTo参数就可以回应客户端。
//服务端
public class MessengerService extends Service {
private class MessengerHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MyConstants.MSG_FROM_CLIENT:
Log.i("lfy", msg.getData().getString("msg"));
Messenger messenger = msg.replyTo;
Message message = Message.obtain(null, MyConstants.MSG_FROM_SERVICE);
Bundle bundle = new Bundle();
bundle.putString("reply", "Hello,I reply");
message.setData(bundle);
try {
messenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
break;
default:
super.handleMessage(msg);
}
}
}
private Messenger mMessenger = new Messenger(new MessengerHandler());
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
}
<service
android:name=".MessengerService"
android:process=":remote" />
//客户端
public class MainActivity extends AppCompatActivity {
private Messenger messenger;
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
messenger = new Messenger(service);
Message message = Message.obtain(null, MyConstants.MSG_FROM_CLIENT);
Bundle data = new Bundle();
data.putString("msg", "Hello,this is client");
message.setData(data);
message.replyTo = getReplyMessenger;
try {
messenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
private class MessengerHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MyConstants.MSG_FROM_SERVICE:
Log.i("lfy", msg.getData().getString("reply"));
break;
default:
super.handleMessage(msg);
}
}
}
private Messenger getReplyMessenger = new Messenger(new MessengerHandler());
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, MessengerService.class);
bindService(intent, conn, Context.BIND_AUTO_CREATE);
}
}
注:Message支持的载体只有what,arg1,arg2,Bundle以及replyTo,其中另一个字段obj在同一个进程中是很实用的,但是在进程中通信时,只支持系统提供的实现了Parcelable接口的,这就意味着自定义的Parcelable对象是无法传递的。所幸Bundle中可以支持大量的数据类型。
()使用AIDL
Messenger是以串行的方式处理客户端发来的消息,如果大量的消息同时发送到服务端,服务端只能一个个处理,如果有大量的并发请求,那么用Messenger就不太合适。同时,Messenger的作用主要是为了传递消息。AIDL的作用主要是用来实现跨进程的方法调用。AIDL也是Messenger的底层实现。因此Messenger本质上也是AIDL。
使用AIDL的方法分为服务端和客户端
服务端:创建一个Service用来监听客户端的连接请求,然后创建一个AIDL文件,将暴露给客户端的接口在这个AIDL文件中声明,最后在Service中实现这个AIDL接口即可。
客户端:首先需要绑定服务端的Service,绑定成功后,将服务端返回的IBinder对象转换成AIDL接口所属的类型,接着就可以调用AIDL中的方法了。
创建AIDL文件的注意点:
()AIDL支持的数据类型
[]基本数据类型
[]String和CharSequence
[]List,只支持ArrayList,里面每个元素都必须能被AIDL支持
[]Map,只支持HashMap,里面的每个元素都必须能被AIDL支持,包括key和value
[]Parcelable,所有实现了Parcelable接口的对象
[]AIDL,所有的AIDL接口本身也是可以在AIDL文件中使用
其中自定义的Parcelable对象和AIDL对象必须要显式import进来,不管它们是否和当前的AIDL文件位于同一个包内。
注:List只支持ArrayList,Map只支持HashMap。说的是方法的返回值和传递参数类型,在方法的实现中可以使用实现List接口的任何类以及实现Map接口的任何类。
()如果AIDL文件中用到了自定义的Parcelable对象,那么必须新建一个和它同名的AIDL文件。并在其声明它为Parcelable类型。
()AIDL中除了基本数据类型,其他类型的参数必须标上方向:in、out或者inout。in标示输入型参数,out表示输出型参数,inout表示输入输出型参数。
()AIDL接口中只支持方法,不支持声明静态常量。
()AIDL的包结构在服务端和客户端要保持一致,否则运行会出错。这是因为客户端需要反序列化服务端中和AIDL接口相关的所有类,如果类的完整路径不一样时,就无法成功反序列化。因而建议将所有和AIDL相关的类和文件全部放到一个包中。
//aidl文件
//Book.aidl
package com.hhb.text.aidl;
parcelable Book;
// IBookManager.aidl
package com.hhb.text.aidl;
import com.hhb.text.aidl.Book;
interface IBookManager {
List<Book> getBookList();
void addBook(in Book book);
}
//服务端
public class BookManagerService extends Service {
private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<>();
private Binder mBinder = new IBookManager.Stub() {
@Override
public List<Book> getBookList() throws RemoteException {
return mBookList;
}
@Override
public void addBook(Book book) throws RemoteException {
mBookList.add(book);
}
};
@Override
public void onCreate() {
super.onCreate();
mBookList.add(new Book(1, "Android"));
mBookList.add(new Book(2, "IOS"));
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
<service
android:name=".service.BookManagerService"
android:process=":aidlRemote" />
CopyOnWriteArrayList支持并发读/写,AIDL方法是在服务端的Binder线程池中执行的。当有多个客户端同时连接时,会存在多个线程同时访问的情形,所以需要在AIDL中处理线程同步,所以直接使用CopyOnWriteArrayList来进行自动的线程同步。
AIDL中能够使用的List只有ArrayList,但是这里是使用CopyOnWriteArrayList(它没有继承ArrayList)为什么能正常工作呢,是因为虽然服务端返回的是CopyOnWriteArrayList,但是在Binder中会按照List的规范去访问数据并最终形成一个新的ArrayList传递给客户端。
//客户端
public class AidlActivity extends Activity {
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
IBookManager bookManager = IBookManager.Stub.asInterface(service);
try {
List<Book> bookList = bookManager.getBookList();
Log.i("aidl", "book:" + bookList.get(0));
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.aidl);
Intent intent = new Intent(this, BookManagerService.class);
bindService(intent, conn, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(conn);
}
}
AIDL观察者模式情况:当服务端添加新的Book时,通知客户端
//aidl文件
//Book.aidl
package com.hhb.text.aidl;
parcelable Book;
// IBookManager.aidl
package com.hhb.text.aidl;
import com.hhb.text.aidl.Book;
import com.hhb.text.aidl.IOnNewBookArrivedListener;
interface IBookManager {
List<Book> getBookList();
void addBook(in Book book);
void registerListener(IOnNewBookArrivedListener listener);
void unregisterListener(IOnNewBookArrivedListener listener);
}
// IOnNewBookArrivedListener.aidl
package com.hhb.text.aidl;
import com.hhb.text.aidl.Book;
interface IOnNewBookArrivedListener {
void onNewBookArrived(in Book newBook);
}
//服务端
public class BookManagerService extends Service {
private AtomicBoolean mIsServiceDestoryed = new AtomicBoolean(false);
private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<>();
private RemoteCallbackList<IOnNewBookArrivedListener> mListener = new RemoteCallbackList<>();
private Binder mBinder = new IBookManager.Stub() {
@Override
public List<Book> getBookList() throws RemoteException {
return mBookList;
}
@Override
public void addBook(Book book) throws RemoteException {
mBookList.add(book);
}
@Override
public void registerListener(IOnNewBookArrivedListener listener) throws RemoteException {
mListener.register(listener);
}
@Override
public void unregisterListener(IOnNewBookArrivedListener listener) throws RemoteException {
mListener.unregister(listener);
}
};
@Override
public void onCreate() {
super.onCreate();
mBookList.add(new Book(1, "Android"));
mBookList.add(new Book(2, "IOS"));
new Thread(new ServiceWorker()).start();
}
private class ServiceWorker implements Runnable {
@Override
public void run() {
while (!mIsServiceDestoryed.get()) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
int bookId = mBookList.size() + 1;
Book book = new Book(bookId, "new book #" + bookId);
try {
onNewBookArrived(book);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
}
private void onNewBookArrived(Book book) throws RemoteException {
mBookList.add(book);
//beginBroadcast()和finishBroadcast()必须配对使用,否则无效
int N = mListener.beginBroadcast();
for (int i = 0; i < N; i++) {
IOnNewBookArrivedListener listener = mListener.getBroadcastItem(i);
if (listener != null) {
listener.onNewBookArrived(book);
}
}
mListener.finishBroadcast();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
@Override
public void onDestroy() {
mIsServiceDestoryed.set(true);
super.onDestroy();
}
}
<service
android:name=".service.BookManagerService"
android:process=":aidlRemote" />
//客户端
public class AidlActivity extends Activity {
private IBookManager bookManager;
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MyConstants.MESSAGE_NEW_BOOK_ARRIVED:
Log.i("aidl", "receive new book : " + msg.obj);
break;
default:
super.handleMessage(msg);
}
}
};
private IOnNewBookArrivedListener listener = new IOnNewBookArrivedListener.Stub() {
@Override
public void onNewBookArrived(Book newBook) throws RemoteException {
if (Looper.getMainLooper() == Looper.myLooper()) {
Log.i("aidl", "onNewBookArrived:主线程");
} else {
Log.i("aidl", "onNewBookArrived:非主线程");
}
mHandler.obtainMessage(MyConstants.MESSAGE_NEW_BOOK_ARRIVED, newBook).sendToTarget();
}
};
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
bookManager = IBookManager.Stub.asInterface(service);
try {
List<Book> bookList = bookManager.getBookList();
Log.i("aidl", "id:" + bookList.get(0).getBookId() + " name:" + bookList.get(0).getBookName());
bookManager.registerListener(listener);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.aidl);
Intent intent = new Intent(this, BookManagerService.class);
bindService(intent, conn, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
if (bookManager != null && bookManager.asBinder().isBinderAlive()) {
try {
bookManager.unregisterListener(listener);
} catch (RemoteException e) {
e.printStackTrace();
}
}
unbindService(conn);
super.onDestroy();
}
}
注:
[]客户端在registerListener()和unregisterListener()传递的是同一个IOnNewBookArrivedListener对象,但是Binder会把客户端跨进程传输(反序列化)的对象重新转化并生成一个新的对象,但是这些新生成的对象有一个共同点:它们底层的Binder对象是同一个,如果服务端将IOnNewBookArrivedListener添加到ArrayList中会导致客户端取消监听时找不到对象。这时需要采用RemoteCallbackList。
[]RemoteCallbackList专门用于删除跨进程Listener的接口。RemoteCallbackList是一个泛型,支持管理任意的AIDL接口。它的内部有一个ArrayMap结构专门用来保存所有的AIDL回调,其中key是IBinder,value是Callback。当客户端注册Listener时,它会把Listener对象的信息存入Callback中。
[]当客户端进程终止后,RemoteCallbackList能自动移除客户端所注册的Listener,另外RemoteCallbackList内部自动实现了线程同步的功能,所以使用它来注册和解注册时,不需要做额外的线程同步工作。
[]客户端调用服务端的方法,被调用的方法在服务端的BInder线程池中。同时客户端线程会被挂起,如果服务端的方法比较耗时,会导致客户端线程长时间的阻塞,如果客户端线程是UI线程,就会导致客户端ANR。同时服务端的方法本来就运行在服务端的Binder线程池中,可以直接执行大量耗时操作。
[]服务端调用客户端的Listener中的方法时。被调用的方法也运行在Binder线程池中,只不过是客户端的线程池,比如客户端的IOnNewBookArrivedListener的onNewBookArrived()运行在客户端的Binder线程池中。所以不能访问UI相关的内容。
[]服务进程意外死亡,重新连接服务方法:第一种方法是给Binder设置DeathRecipient监听,第二种方式是在onServiceDisconnected()重新连接服务。区别是DeathRecipient监听是在客户端的Binder线程池中被回调,onServiceDisconnected()是在客户端的UI线程中被回调。
[]AIDL权限验证:第一种方法在onBind()中进行验证,验证不通过就返回null,这样验证失败的客户端直接无法绑定服务,至于验证的方式有多种,比如使用permissions验证。第二种方法在服务端的onTransact()中进行权限验证,如果验证失败就直接返回false,这样服务端就不会终止执行AIDL中的方法从而达到保护服务端的方法。至于验证的方式有多种,可以采用permissions验证,还可以采用Uid和Pid来做验证。
()使用ContentProvider
ContentProvider是用于不同应用间进行数据共享的方式,ContentProvider的底层实现也是Binder。
ContentProvider的onCreate()由系统调用并运行在主线程中,因此不能在onCreate()中执行耗时操作。getType(),insert(),delete(),update(),query()都由外界调用并运行在Binder线程池中,所以是存在多线程并发访问的。因此需要做好线程同步。
ContentProvider还支持自定义调用,这个过程是通过ContentProvider的call()和ContentResolver的call()来完成的。
其余的就是ContentProvider的基本使用。
()使用Socket
其实就是Socket的基本使用。
[]Binder连接池
Binder连接池的工作机制:每个业务模块创建自己的AIDL接口并实现。这时不同的业务模块之间是不能有耦合的,所有实现细节要单独分开。然后向服务端提供唯一的标识和对应的Binder对象;对于服务端来说,只需要一个Service。服务端提供一个queryBinder接口。这个接口能根据业务模块的特征来返回对应的Binder对象给它们。不同的业务模块拿到所需的BInder对象后就可以进行远程方法调用。Binder连接池的主要作用就是将每个业务模块的Binder请求统一转发到远程Service中去执行,从而避免了重复创建Service的过程。
业务aild
// ISecurityCenter.aidl
package com.hhb.text.aidl;interface ISecurityCenter {
String encrypt(String content);
String decrypt(String password);
}
// ICompute.aidl
package com.hhb.text.aidl;interface ICompute {
int add (int a,int b);
}
业务aidl的实现类
public class ISecurityCenterImpl extends ISecurityCenter.Stub {
@Override
public String encrypt(String content) throws RemoteException {
Log.i("aidl", " ISecurityCenterImpl encrypt:" + content);
return " ISecurityCenterImpl encrypt:" + content;
}
@Override
public String decrypt(String password) throws RemoteException {
Log.i("aidl", "ISecurityCenterImpl decrypt:" + password);
return "ISecurityCenterImpl decrypt:" + password;
}
}
public class IComputeImpl extends ICompute.Stub {
@Override
public int add(int a, int b) throws RemoteException {
Log.i("aidl", " IComputeImpl add:" + (a + b));
return a + b;
}
}
Binder连接池aidl
// IBinderPool.aidl
package com.hhb.text.aidl;
interface IBinderPool {
IBinder queryBinder(int binderCode);
}
Binder连接池aidl实现类
public class IBinderPoolImpl extends IBinderPool.Stub {
@Override
public IBinder queryBinder(int binderCode) throws RemoteException {
IBinder binder = null;
switch (binderCode) {
case MyConstants.BINDER_SECURITY_CENTER:
binder = new ISecurityCenterImpl();
break;
case MyConstants.BINDER_COMPUTE:
binder = new IComputeImpl();
break;
}
return binder;
}
}
服务端
public class BinderPoolService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return new IBinderPoolImpl();
}
}
<service
android:name=".service.BinderPoolService"
android:process=":poolRemote" />
Binder连接池:在构造方法中绑定远程服务,绑定成功后,客户端可以通过它的queryBinder()获取对应的Binder对象。
public class BinderPool {
private Context mContext;
private IBinderPool mBinderPool;
private static volatile BinderPool sInstance;
private CountDownLatch mCountDownLatch;
private BinderPool(Context context) {
this.mContext = context.getApplicationContext();
connectBinderPoolService();
}
public static BinderPool getsInstance(Context context) {
if (sInstance == null) {
synchronized (BinderPool.class) {
if (sInstance == null) {
sInstance = new BinderPool(context);
}
}
}
return sInstance;
}
private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
mBinderPool.asBinder().unlinkToDeath(mDeathRecipient, 0);
mBinderPool = null;
connectBinderPoolService();
}
};
private ServiceConnection mBinderPoolConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mBinderPool = IBinderPool.Stub.asInterface(service);
try {
mBinderPool.asBinder().linkToDeath(mDeathRecipient, 0);
} catch (RemoteException e) {
e.printStackTrace();
}
mCountDownLatch.countDown();
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
private synchronized void connectBinderPoolService() {
/**
* CountDownLatch可以将bindService()这个异步操作转换为同步操作,
* 这就意味着它可能是耗时。
*/
mCountDownLatch = new CountDownLatch(1);
Intent intent = new Intent(mContext, BinderPoolService.class);
mContext.bindService(intent, mBinderPoolConnection, Service.BIND_AUTO_CREATE);
try {
mCountDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public IBinder queryBinder(int binderCode) {
IBinder binder = null;
try {
if (mBinderPool != null) {
binder = mBinderPool.queryBinder(binderCode);
}
} catch (RemoteException e) {
e.printStackTrace();
}
return binder;
}
}
客户端
public class BinderPoolActivity extends Activity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new Thread(new Runnable() {
@Override
public void run() {
BinderPool mBinderPool = BinderPool.getsInstance(BinderPoolActivity.this);
IBinder securityBinder = mBinderPool.queryBinder(MyConstants.BINDER_SECURITY_CENTER);
IBinder computeBinder = mBinderPool.queryBinder(MyConstants.BINDER_COMPUTE);
ISecurityCenter securityCenter = ISecurityCenterImpl.asInterface(securityBinder);
ICompute compute = IComputeImpl.asInterface(computeBinder);
try {
securityCenter.encrypt("11");
securityCenter.decrypt("22");
compute.add(2, 2);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}).start();
}
}
新的业务模块需要添加新的aidl,同时实现自己的aidl接口,只需要修改IBinderPoolImpl的queryBinder(),添加一个新的binderCode并返回对应的Binder对象即可。
[]选用合适的IPC方式
Bundle 优点:简单易用。缺点:只能传输Bundle支持的数据类型。使用场景:四大组件间的进程间通信。
文件共享 优点:简单易用。缺点:不适合高并发场景,并且无法做到进程间的即时通信。使用场景:无并发访问情形,交换简单的数据实时性不高的场景。
Messenger 优点:功能一般,支持一对多串行通信,支持实时通信。缺点:不能很好处理高并发情形,不支持RPC,数据通过Message进行传输,因此只能传输Bundle支持的数据类型。使用场景:低并发的一对多即时通信。无RPC需求,或者无须要返回结果的RPC需求。
AIDL 优点:功能强大,支持一对多并发通信,支持实时通信。缺点:使用稍复杂,需要处理好线程同步。使用场景:一对多通信且有RPC需求。
ContentProvider 优点:在数据源访问方面功能强大,支持一对多并发数据共享,可通过Call方法扩展其他操作。缺点:可以理解为受约束的AIDL,主要提供数据源的CRUD操作。使用场景:一对多的进程间的数据共享。
Socket 优点:功能强大,可以通过网络传输字节流,支持一对多并发实时通信。缺点:实现细节稍微有点繁琐,不支持直接的RPC。使用场景:网络数据交换。
[]in out inout的区别
官网的解释:所有非基本数据类型的参数在传递的时候都需要指定一个方向tag来指明数据的流向,可以是in、out或者inout。基本数据类型默认是in,还不能修改为其他的。还附带了一个警告,你应该根据实际需要来限制方向,因为参数的开销是很大的。
// IBookIntOut.aidl
package com.hhb.text.aidl;
import com.hhb.text.aidl.Book;
interface IBookIntOut {
//分别用in,out,inout标识Book对象
void inBook(in Book book);
void outBook(out Book book);
void inoutBook(inout Book book);
}
注:当有out标识时需要在Book.java中添加Book()和readFromParcel()
public Book() {
}
public void readFromParcel(Parcel in) {
bookId = in.readInt();
bookName = in.readString();
}
()in
@Override
public void inBook(com.hhb.text.aidl.Book book) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((book != null)) {
//book参数不是null时,写入1
_data.writeInt(1);
//将book参数序列化到_data中
book.writeToParcel(_data, 0);
} else {
//book参数是null时,写入0
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_inBook, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
采用in时,客户端传递的参数被序列化到_data中,服务端的onTransact()能收到发起远程调用传的参数。
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
switch (code) {
......
case TRANSACTION_inBook: {
data.enforceInterface(DESCRIPTOR);
com.hhb.text.aidl.Book _arg0;
//通过读取客服端的transact()中写入的int值来判断是否有参数
if ((0 != data.readInt())) {
//将客户端传递的book参数反序列化
_arg0 = com.hhb.text.aidl.Book.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
//调用服务端的inBook()
this.inBook(_arg0);
reply.writeNoException();
return true;
}
......
}
return super.onTransact(code, data, reply, flags);
}
采用in时,在服务端的inBook()中得到与客户端inBook()实参值相同的对象(注意不是同一个对象,Bider会将对象序列化和反序列化)。
()out
@Override
public void outBook(com.hhb.text.aidl.Book book) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
//没有将book参数写入_data中
mRemote.transact(Stub.TRANSACTION_outBook, _data, _reply, 0);
_reply.readException();
//判断服务端的回写值
if ((0 != _reply.readInt())) {
//从_reply反序列化出服务端onTransact()写入reply值,
//所以我们传的实参被修改了(book值被_reply对象修改),
book.readFromParcel(_reply);
}
} finally {
_reply.recycle();
_data.recycle();
}
}
采用out,客户端传递的实参不会传递到服务端,并且,如果 _reply.readInt()这个值不为0,我们传的参数还会被反序列化修改掉。
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
switch (code) {
......
case TRANSACTION_outBook: {
data.enforceInterface(DESCRIPTOR);
com.hhb.text.aidl.Book _arg0;
//没有从data中读取参数的过程,而是new一个新的对象
_arg0 = new com.hhb.text.aidl.Book();
//将new出来的对象直接传给服务端的outBook()
this.outBook(_arg0);
reply.writeNoException();
if ((_arg0 != null)) {
//有参数回写,标记1
reply.writeInt(1);
//将_arg0对象序列化到reply中
_arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} else {
//没有参数回写,标记0
reply.writeInt(0);
}
return true;
}
......
}
return super.onTransact(code, data, reply, flags);
}
采用out,客户端在发起远程调用时传入的实参不会传到到服务端,而是在服务端新建一个对象(调用无参的构造方法来新建对像)传给目标方法,待目标方法返回后将这个对象传回客户端。这意味着目标方法参数所对应的类必须有有无参的构造方法。
()inout
@Override
public void inoutBook(com.hhb.text.aidl.Book book) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((book != null)) {
_data.writeInt(1);
//将book参数序列化到_data中,与in一致
book.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_inoutBook, _data, _reply, 0);
_reply.readException();
if ((0 != _reply.readInt())) {
//将服务端写入reply的值反序列化,修改客户端对象,与out一致
book.readFromParcel(_reply);
}
} finally {
_reply.recycle();
_data.recycle();
}
}
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
switch (code) {
......
case TRANSACTION_inoutBook: {
data.enforceInterface(DESCRIPTOR);
com.hhb.text.aidl.Book _arg0;
if ((0 != data.readInt())) {
//将客户端传递的book参数反序列化
_arg0 = com.hhb.text.aidl.Book.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
this.inoutBook(_arg0);
reply.writeNoException();
if ((_arg0 != null)) {
reply.writeInt(1);
//将_arg0序列化到repley,客户端将反序列化出来
_arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} else {
reply.writeInt(0);
}
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
服务端既读取了客户端传过来的数据(没有new对象,不具备out这点特性),并将参数回写给客户端。
注:
采用in时,经序列化后传递服务端,服务端反序列化得到一个与之值相同的新的对象。大部分情况都是用的in。
采用out时,客户端不会序列化该参数,而是服务端调用无参构造方法新建了一个对象,待目标方法返回后,将参数写入reply返回给客户端。
采用inout时,inout基本上算是in、out的并集,为什么说基本上,因为out会在服务端通过new关键字来新建一个对象,而inout已经通过反序列化客户端传过来的数据得到一个新的对象,就没有必要再new一个了。
[]oneway关键字
如果在方法前面上关键字 oneway,当客户端调用transact后,线程不会被挂起等待服务端返回。但是方法的返回值类型是void并且方法实参采用的是in。