读书笔记(2) IPC机制-2

这些读书笔记是根据《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。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值