由于自己搭建了博客最近都没有在csdn发过博客了,现在发一篇自己的学习笔记,具体内容参照:

Android的IPC机制

Inter-Process Communication => 进程间通信

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

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

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

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

    Serializable

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

    private static final long serialVersionUID = 42L;

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

    eg:

    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;  }}

    传递对象:

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

    写出/读入对象:

    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](https://developer.android.google.cn/reference/android/os/Parcelable.Creator)
  • 需要实现的接口,包括以下方法:

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

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

    eg:

    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方法相同

    Binder

    Android 接口定义语言 (AIDL)

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

    IBookManager.aidl:

    // IBookManager.aidlpackage io.github.grooters.practicer.BindeRer;import io.github.grooters.practicer.BindeRer.Book;// Declare any non-default types here with import statementsinterface 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:

    /* * This file is auto-generated.  DO NOT MODIFY. * Original file: D:\\Android\\Source\\Practicer\\app\\src\\main\\aidl\\io\\github\\grooters\\practicer\\BindeRer\\IBookManager.aidl */package io.github.grooters.practicer.BindeRer;// Declare any non-default types here with import statementspublic interface IBookManager extends android.os.IInterface {/** Local-side IPC implementation stub class. */    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";        /** Construct the stub at attach it to the interface. */        public Stub(){          this.attachInterface(this, DESCRIPTOR);        }        /**         * Cast an IBinder object into an io.github.grooters.practicer.BindeRer.IBookManager interface,         * generating a proxy if needed.         */        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;            }            /**             * Demonstrates some basic types that you can use as parameters             * and return values in AIDL.             */            @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

    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中:

    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工作机制:

    跨进程方式

    Messenger

    客户端:

    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传过给服务端。

    服务端:

    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对象,通过该对象服务端可以向客户端发送消息。

    AIDL

    服务端:

    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,实现提供给客户端调用的方法

    客户端:

    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的监听(如监听者模式),该类就提供了解决方案

    private RemoteCallbackList<BookArrivedListener> bookArrivedListeners=new RemoteCallbackList<>();@Overridepublic void registerListener(BookArrivedListener listener) throws RemoteException {    bookArrivedListeners.register(listener);}@Overridepublic void unRegisterListener(BookArrivedListener listener) throws RemoteException {    bookArrivedListeners.unregister(listener);}

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

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

    权限验证

  • 在onBinder中验证
  • 服务端:

    <permission android:name="io.github.grooters.practicer.BindeRer.ACCESS_BOOK"    android:protectionLevel="normal"/>
    @Nullable@Overridepublic 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指具备该权限

    客户端:

    <uses-permission android:name="io.github.grooters.practicer.BindeRer.ACCESS_BOOK"/>
  • 在onBinder中验证
  • 服务端:

    @Overridepublic 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

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

    更多相关文章

    1. Android中一个Activity多个intent-filter的调用方法
    2. Android模拟SD卡实现方法解析
    3. Android编程实现屏幕自适应方向尺寸与分辨率的方法
    4. Android Studio导入Project的方法
    5. Android使用AudioRecord遇到的问题与解决方法
    6. struts2服务端与android交互
    7. 另类方法屏蔽Android4.03的HOME按键
    8. android SDK更新方法总结
    9. android设置Activity背景色为透明的2种方法

    随机推荐

    1. Android使用AIDL实现进程间通信
    2. Android(安卓)UI控件之 焦点问题
    3. Android Platform 3.0 SDK和Eclipse ADT
    4. 【Service 1】Android(安卓)Remote Servi
    5. 关于Android设备屏幕大小及密度的系统参
    6. Android:简易弹幕效果实现,android弹幕
    7. Android成长(二)——两个页面交互
    8. Android开发小技巧之------------如何不
    9. Android笔记-自定义适配器
    10. 在android使用OPENGL总结