Android的IPC机制

由于自己搭建了博客最近都没有在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.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:

    /*
     * 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 statements
    
    public 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工作机制:

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

    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<>();
    @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:

    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
    @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指具备该权限

    客户端:

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

    @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

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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值