盒子
盒子
文章目录
  1. Serializable
  2. Parceleable
    1. Serializable和Parceleable的区别
  3. Binder
    1. Android 接口定义语言 (AIDL)
    2. 跨进程方式
      1. Messenger
      2. AIDL
      3. ContentProvider
      4. Socket

Android的IPC机制

Inter-Process Communication => 进程间通信

  • app多进程的开启
  • 在定义四大组件时添加如下属性:

    1
    2
    android:process=":remote"
    android:process="io.github.grooters.remote"

    :remote指当前app的包名, .remote私有进程

    由于开启多进程后,处于不同进程的组件会导致数据无法通信问题,故需要通过以下方式实现IPC

    Serializable

    用于实现Serializable接口的类可通过Intent和Binder进行传递

    1
    private static final long serialVersionUID = 42L;

    该长整形静态常量用于辅助序列化与反序列化操作,通过识别该id可判断对象是否发生改变

    eg:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    public class Serializabler implement Serializable{
    private static final long serialVersionUID = 42L;
    private int id;
    private String name;
    public String getName() {
    return name;
    }
    public void setName(String name) {
    this.name = name;
    }
    public int getId() {
    return id;
    }
    public void setId(int id) {
    this.id = id;
    }
    }

    传递对象:

    1
    2
    bundle.putSerializable("key",serializabler);
    intent.putExtra("key",bundle);

    写出/读入对象:

    1
    2
    3
    4
    5
    6
    try {
    ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/test.text")));
    outputStream.writeObject(serializabler);
    }catch (IOException e){
    e.printStackTrace();
    }

    Parceleable

    需要重写四个方法:

  • public int describeContents()
  • 内容描述,无描述返回0,有描述返回CONTENTS_FILE_DESCRIPTOR(1)

  • public abstract void writeToParcel(Parcel dest,int flags)
  • 序列化方法

  • Parcelable.Creator
  • 需要实现的接口,包括以下方法:

  • public abstract T createFromParcel(Parcel source)
  • 反序列化

  • public abstract T [] newArray(int size)
  • 创建一个Parceleable类型的新数组

    eg:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    package io.github.grooters.practicer;

    import android.os.Parcel;
    import android.os.Parcelable;

    /**
    * Create by 李林浪 in 2018/10/24
    * Elegant Code...
    */
    public class Parceleabler implements Parcelable {
    private String name;
    private int id;
    private int sex;
    public String getName() {
    return name;
    }
    public void setName(String name) {
    this.name = name;
    }
    public int getId() {
    return id;
    }
    public void setId(int id) {
    this.id = id;
    }
    public int getSex() {
    return sex;
    }
    public void setSex(int sex) {
    this.sex = sex;
    }
    public static final Parcelable.Creator<Parceleabler> CREATOR=new Parcelable.Creator<Parceleabler>(){
    @Override
    public Parceleabler createFromParcel(Parcel source) {
    Parceleabler parceleabler=new Parceleabler();
    //顺序要和序列化的write操作一样
    parceleabler.setId(source.readInt());
    parceleabler.setName(source.readString());
    parceleabler.setSex(source.readInt());
    return parceleabler;
    }

    @Override
    public Parceleabler[] newArray(int size) {
    return new Parceleabler[size];
    }
    };
    @Override
    public int describeContents() {
    return 0;
    }
    @Override
    public void writeToParcel(Parcel dest, int flags) {
    dest.writeInt(id);
    dest.writeString(name);
    dest.writeInt(sex);
    }
    }

    传递和写出读入方法和Serializable方法相同

    Serializable和Parceleable的区别

    Serializable是由Java提供的序列化接口直接实现使用,但使用到了反射以及基于外存读取所以效率低

    Parceleable是由Android提供的序列化接口使用较为复杂,但效率远远高于Serializable

    Binder

    Android 接口定义语言 (AIDL)

    新建一个AIDL文件系统会自动生成对应的java文件,eg:

    IBookManager.aidl:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // IBookManager.aidl
    package io.github.grooters.practicer.BindeRer;
    import io.github.grooters.practicer.BindeRer.Book;
    // Declare any non-default types here with import statements
    interface IBookManager {
    /**
    * Demonstrates some basic types that you can use as parameters
    * and return values in AIDL.
    */
    List<Book> getBookList();
    void addBook(in Book book);
    }

    IBookManager.java:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    package io.github.grooters.practicer.BindeRer;
    public interface IBookManager extends android.os.IInterface {
    public static abstract class Stub extends android.os.Binder implements io.github.grooters.practicer.BindeRer.IBookManager {
    private static final java.lang.String DESCRIPTOR = "io.github.grooters.practicer.BindeRer.IBookManager";
    public Stub(){
    this.attachInterface(this, DESCRIPTOR);
    }
    public static io.github.grooters.practicer.BindeRer.IBookManager asInterface(android.os.IBinder obj) {
    if ((obj==null)) {
    return null;
    }
    android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
    if (((iin!=null)&&(iin instanceof io.github.grooters.practicer.BindeRer.IBookManager))) {
    return ((io.github.grooters.practicer.BindeRer.IBookManager)iin);
    }
    return new io.github.grooters.practicer.BindeRer.IBookManager.Stub.Proxy(obj);
    }
    @Override
    public android.os.IBinder asBinder(){
    return this;
    }
    @Override
    public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
    switch (code) {
    case INTERFACE_TRANSACTION: {
    reply.writeString(DESCRIPTOR);
    return true;
    }
    case TRANSACTION_getBookList: {
    data.enforceInterface(DESCRIPTOR);
    java.util.List<io.github.grooters.practicer.BindeRer.Book> _result = this.getBookList();
    reply.writeNoException();
    reply.writeTypedList(_result);
    return true;
    }
    case TRANSACTION_addBook: {
    data.enforceInterface(DESCRIPTOR);
    io.github.grooters.practicer.BindeRer.Book _arg0;
    if ((0!=data.readInt())) {
    _arg0 = io.github.grooters.practicer.BindeRer.Book.CREATOR.createFromParcel(data);
    }
    else {
    _arg0 = null;
    }
    this.addBook(_arg0);
    reply.writeNoException();
    return true;
    }
    }
    return super.onTransact(code, data, reply, flags);
    }
    private static class Proxy implements io.github.grooters.practicer.BindeRer.IBookManager {
    private android.os.IBinder mRemote;
    Proxy(android.os.IBinder remote){
    mRemote = remote;
    }
    @Override
    public android.os.IBinder asBinder(){
    return mRemote;
    }
    public java.lang.String getInterfaceDescriptor(){
    return DESCRIPTOR;
    }
    @Override
    public java.util.List<io.github.grooters.practicer.BindeRer.Book> getBookList() throws android.os.RemoteException {
    android.os.Parcel _data = android.os.Parcel.obtain();
    android.os.Parcel _reply = android.os.Parcel.obtain();
    java.util.List<io.github.grooters.practicer.BindeRer.Book> _result;
    try {
    _data.writeInterfaceToken(DESCRIPTOR);
    mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
    _reply.readException();
    _result = _reply.createTypedArrayList(io.github.grooters.practicer.BindeRer.Book.CREATOR);
    }
    finally {
    _reply.recycle();
    _data.recycle();
    }
    return _result;
    }
    @Override
    public void addBook(io.github.grooters.practicer.BindeRer.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.writeToParcel(_data, 0);
    }
    else {
    _data.writeInt(0);
    }
    mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
    _reply.readException();
    }
    finally {
    _reply.recycle();
    _data.recycle();
    }
    }
    }
    static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    }
    public java.util.List<io.github.grooters.practicer.BindeRer.Book> getBookList() throws android.os.RemoteException;
    public void addBook(io.github.grooters.practicer.BindeRer.Book book) throws android.os.RemoteException;
    }

  • asInterface (android.os.IBinder obj)
  • 将服务端Binder对象转换成客户端所需的AIDL接口类型的对象,若客户端和服务端在不同进程,则返回的是Stub.Proxy

    1
    2
    3
    4
    5
    android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
    if (((iin!=null)&&(iin instanceof io.github.grooters.practicer.BindeRer.IBookManager))) {
    return ((io.github.grooters.practicer.BindeRer.IBookManager)iin);
    }
    return new io.github.grooters.practicer.BindeRer.IBookManager.Stub.Proxy(obj);

  • android.os.IBinder asBinder()
  • 返回当前的Binder对象(实现了IBinder接口)

  • onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)
  • 运行在服务端的Binder线程池中,当跨进程访问时会通过code判断出使用哪个方法,当方法执行后,会将_result结果写入到reply中:

    1
    2
    3
    4
    java.util.List<io.github.grooters.practicer.BindeRer.Book> _result = this.getBookList();
    reply.writeNoException();
    reply.writeTypedList(_result);
    return true;

    当返回false时表示请求失败

  • 客户端定义的方法(getBookList,addBook)
  • 方法中含有输入Paecel对象_data,输出Parcel对象_reply和返回值对象,其中方法参数会写入_data对象,然后调用transact方法发起RPC(远程过程调用)请求,此时该线程会挂起,直到onTransact中对应的方法执行并返回reply才会重写激活线程,此时可从_reply中获取对应的结果

    Binder工作机制:

    Binder工作机制

    跨进程方式

    Messenger

    客户端:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    Intent intent=new Intent(this,Servicer.class);
    bindService(intent,serviceConnection, Context.BIND_AUTO_CREATE);
    ServiceConnection serviceConnection=new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
    Messenger reply=new Messenger(new MessengerHandler());
    Messenger messenger=new Messenger(service);
    Message msg=Message.obtain();
    msg.replyTo=reply;
    try {
    messenger.send(msg);
    } catch (RemoteException e) {
    e.printStackTrace();
    }
    }
    @Override
    public void onServiceDisconnected(ComponentName name) {}
    };
    private static class MessengerHandler extends Handler{
    @Override
    public void handleMessage(Message msg) {
    super.handleMessage(msg);
    Log.i(TAG,"handleMessage");
    }
    }

    创建一个绑定了Binder的Messenger对象用于发送消息,再创建一个绑定了MessengerHandler的Messenger对象并作为replyTo传过给服务端。

    服务端:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    public class Servicer extends Service {
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
    return super.onStartCommand(intent, flags, startId);
    }
    private static class MessagerHandler extends Handler{
    @Override
    public void handleMessage(Message msg) {
    super.handleMessage(msg);
    Messenger client=msg.replyTo;
    Message message=Message.obtain();
    try {
    client.send(message);
    } catch (RemoteException e) {
    e.printStackTrace();
    }
    }
    }
    Messenger messenger=new Messenger(new MessagerHandler());
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
    return messenger.getBinder();
    }
    @Override
    public boolean onUnbind(Intent intent) {
    return super.onUnbind(intent);
    }
    }

    服务端收到消息后从Message中取出客户端存入的replyTo即绑定了客户端Handler的Messenger对象,通过该对象服务端可以向客户端发送消息。

    Messenger的工作原理

    AIDL

    服务端:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    public class Servicer extends Service {
    IBinder iBookManager=new IBookManager.Stub() {
    @Override
    public List<Book> getBookList() throws RemoteException {
    Log.i(TAG,"getBookList()");
    return null;
    }
    @Override
    public void addBook(Book book) throws RemoteException {
    Log.i(TAG,"book.id:"+book.getId());
    }
    @Override
    public IBinder asBinder() {
    return this;
    }
    };
    }

    实例化通过AIDL定义自动生成的Java类中的内部类IBookManager.Stub,实现提供给客户端调用的方法

    客户端:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    Intent intent=new Intent(this,Servicer.class);
    ServiceConnection serviceConnection=new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
    Log.i(TAG,"onServiceConnected");
    IBookManager bookManager=IBookManager.Stub.asInterface(service);
    try {
    final Book book=new Book();
    book.setId(5);
    bookManager.addBook(book);
    } catch (RemoteException e) {
    e.printStackTrace();
    }
    }
    @Override
    public void onServiceDisconnected(ComponentName name) {}
    };

    通过调用IBookManager.Stub类中的asInterface方法传入服务端返回的IBinder对象获得IBookManager对象,通过该对象便可调用服务端方法

    RemoteCallbackList

    由于跨进程通讯,从客户端传到服务端的对象会被重建(序列化和反序列化),所以无法通过简单的对象判断来识别是否是同一个对象,针对某种情况需要注销对某个listener的监听(如监听者模式),该类就提供了解决方案

    1
    2
    3
    4
    5
    6
    7
    8
    9
    private RemoteCallbackList<BookArrivedListener> bookArrivedListeners=new RemoteCallbackList<>();
    @Override
    public void registerListener(BookArrivedListener listener) throws RemoteException {
    bookArrivedListeners.register(listener);
    }
    @Override
    public void unRegisterListener(BookArrivedListener listener) throws RemoteException {
    bookArrivedListeners.unregister(listener);
    }

    该类为map结构实现对listnner的存储,通过IBinder作为key值,通过Callback保存listnner后作为value:

    1
    2
    IBinder key=listner.asBinder()
    Callback value=new Callback(listener,cookies)

    权限验证

  • 在onBinder中验证
  • 服务端:

    1
    2
    <permission android:name="io.github.grooters.practicer.BindeRer.ACCESS_BOOK"
    android:protectionLevel="normal"/>
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
    Log.i(TAG,"onBind");
    int check=checkCallingOrSelfPermission("io.github.grooters.practicer.BindeRer.ACCESS_BOOK");
    if(check==PackageManager.PERMISSION_DENIED){
    Log.i(TAG,"check==PackageManager.PERMISSION_DENIED");
    return null;
    }
    return iBookManager;
    }

    checkCallingOrSelfPermission判断是否具有某项权限,有返回0,没有返回1

    PackageManager.PERMISSION_DENIED指不具备该权限

    PackageManager.PERMISSION_GRANTED指具备该权限

    客户端:

    1
    <uses-permission android:name="io.github.grooters.practicer.BindeRer.ACCESS_BOOK"/>

  • 在onBinder中验证
  • 服务端:

    1
    2
    3
    4
    5
    6
    7
    8
    @Override
    public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
    int check = checkCallingPermission("io.github.grooters.practicer.BindeRer.ACCESS_BOOK");
    if(check == PackageManager.PERMISSION_DENIED){
    return false;
    }
    return super.onTransact(code, data, reply, flags);
    }

    深入了解Binder可参看这篇文章:

    Android跨进程通信:图文详解 Binder机制 原理

    ContentProvider

    具体参考内容提供器的使用

    Socket

    支持一下
    扫一扫,支持Grooter
    • 微信扫一扫
    • 支付宝扫一扫