美文网首页程序员
Android IPC(进程间通信)

Android IPC(进程间通信)

作者: 瓶子狗坏人 | 来源:发表于2019-04-10 08:53 被阅读0次

    关于Android 进程间通信的基本知识以及Android中进程间通信的方式

    IPC简介与基础概念

    基础

    • android 开启多进程的方式
      1. 指定四大组件的 android:process 属性
      2. 通过Jninative层 fork一个进程
    • "anroid:process" 进程命名的含义
      1. ":"开头表示当前进程名前面要加上包名
      2. ":" 表示是当前应用的私有进程,其它应用的组件不可以和它跑在同一个进程中
      3. 没有 ":" 表示是全局进程,其它应用的组件在ShareUID并且签名相同的情况下也可以跑在这个进程
    • 多进程会带来的问题
      1. 静态成员和单例模式失效
      2. Application 会创建多次
      3. SharedPreference 变得不可靠
      4. 线程同步机制失效
    • Serializable , Parcelable
    1. Serializable

      /**
       * 父类没有实现Serializable,子类实现了Serializable,父类的属性不会参与序列化
       */
      open class Parent(var parentName: String) {
          constructor() : this("parent")
      }
      
      /**
       * 定义[readObject] 和[writeObject] 可以对序列化进行一些自定义的操作
       */
      data class Child(
          var childName: String = "Bob",
          //有Transient标识的 不参与序列化
          @Transient var childAge: Int = 5,
          var password: String = "password"
      ) : Serializable, Parent() {
          companion object {
              /**
               * 1.在反序列化的时候,只有这个值相同的情况下才有可能反序列化成功
               * 2.可以不指定这个值,系统会有默认值
               * 3.在默认值的情况下,如果增加和删除了成员变量,反序列化不能成功,默认值改变了
               * 4.如果类名发生改变或成员的类型发生改变,不管这个值是相同,反序列化都不能成功
               * */
              private const val serialVersionUID = 2L
          }
          /**
           * 反序列化操作
           * 默认会调用 [java.io.ObjectInputStream.defaultReadObject]
           *
           * */
          private fun readObject(ins: ObjectInputStream) {
              try {
                  val fields = ins.readFields()
                  password = fields.get("password", "").toString()
              } catch (e: Exception) {
                  Log.d("SerialTest", e.message ?: "UnKnowError")
              }
          }
      
          /**
           * 序列化操作
           * 默认会调用 [java.io.ObjectOutputStream.defaultWriteObject]
           *
           * */
          private fun writeObject(out: ObjectOutputStream) {
              try {
                  val fields = out.putFields()
                  fields.put("password", password + "encryption")
                  //  fields.put("childName",childName)
                  out.writeFields()
              } catch (e: Exception) {
                  Log.d("SerialTest", e.message ?: "UnKnowError")
              }
          }
      }
         
      
    2. Parcelable

      /**
       * 必须与相应的AIDL在同个包下
       */
      data class Info(var data: String,
                      var times: Int) : Parcelable {
          companion object CREATOR : Parcelable.Creator<Info> {
              /**
               * 从序列化的对象中创建原始对象
               * */
              override fun createFromParcel(source: Parcel): Info = Info(source)
      
              /**
               * 创建指定长度的原始对象数组
               * */
              override fun newArray(size: Int): Array<Info?> = arrayOfNulls(size)
          }
      
          constructor(parcel: Parcel) : this(
                  parcel.readString() ?: "",
                  parcel.readInt())
      
          /**
           * 将当前对象写入序列化对象中
           * @param flags  1表示当前对象需要最为返回值返回,不能立即释放,几乎所有情况都为0
           * [android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE]
           * */
          override fun writeToParcel(dest: Parcel?, flags: Int) {
              dest?.apply {
                  writeString(data)
                  writeInt(times)
              }
          }
      
          /**
           * @retrun 如果有文件描述符返回1, 否则返回0(几乎所有情况都是0)
           * [android.os.Parcelable.CONTENTS_FILE_DESCRIPTOR]
           * */
          override fun describeContents() = 0
      }
      
      

    Binder

    NOTE:
    1. 客户端在RPC(远程请求调用)的时候,会挂起当前线程直到RPC返回后才会重新唤醒,所以客户端启动的RPC是耗时任务时务必要新开一个线程
    2. 服务端相关的方法已经运行在Binder的线程池中,就算是耗时任务也不需要新开一个线程
    3. 同理在服务端发起RPC时也会挂起服务端的当前线程,此时调用到的客户端的方法运行在客户端的Binder线程池中,涉及到UI操作时要做切换线程处理(可以使用Handler);如果是耗时操作,服务端务必不要在主线程中发起此RPC

    • 通过AIDL了解Binder
       package com.open.aqrlei.ipc.aidl;
       
       public interface IChangeListener extends android.os.IInterface {
           /**
            * Local-side IPC implementation stub class.
            */
           public static abstract class Stub extends android.os.Binder implements com.open.aqrlei.ipc.aidl.IChangeListener {
               /**
                * Binder的唯一标识
                */
               private static final java.lang.String DESCRIPTOR = "com.open.aqrlei.ipc.aidl.IChangeListener";
       
               /**
                * Construct the stub at attach it to the interface.
                */
               public Stub() {
                   this.attachInterface(this, DESCRIPTOR);
               }
       
               /**
                * @return
                * 将服务端的Binder对象转换成客户端所需的AIDL接口对象。
                * 如果是同一进程中,此方法返回的是服务端的Stub对象本生
                * 如果是不同进程,返回的是系统封装后的Stub.proxy对象
                */
               public static com.open.aqrlei.ipc.aidl.IChangeListener asInterface(android.os.IBinder obj) {
                   if ((obj == null)) {
                       return null;
                   }
                   android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
                   if (((iin != null) && (iin instanceof com.open.aqrlei.ipc.aidl.IChangeListener))) {
                       return ((com.open.aqrlei.ipc.aidl.IChangeListener) iin);
                   }
                   return new com.open.aqrlei.ipc.aidl.IChangeListener.Stub.Proxy(obj);
               }
       
               /**
                * @return 返回当前的 Binder对象
                */
               @Override
               public android.os.IBinder asBinder() {
                   return this;
               }
       
               /**
                * 运行在服务端的Binder线程池中,当客户端发起跨进程请求时,远程请求通过系统底层封装后交由此方法处理
                * {@link android.os.Binder}
                * @param code  服务端通过code可以确定所请求的方法是什么
                * @param data  从data中取出目标方法所需要的参数(如果需要的话),然后执行目标方法
                * @param reply 在reply中写入返回值(如果需要的话)
                * @return 返回 false ,客户端的请求就会失败
                * */
               @Override
               public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
                   java.lang.String descriptor = DESCRIPTOR;
                   switch (code) {
                       case INTERFACE_TRANSACTION: {
                           reply.writeString(descriptor);
                           return true;
                       }
                       case TRANSACTION_msgChange: {
                           data.enforceInterface(descriptor);
                           com.open.aqrlei.ipc.Info _arg0;
                           if ((0 != data.readInt())) {
                               _arg0 = com.open.aqrlei.ipc.Info.CREATOR.createFromParcel(data);
                           } else {
                               _arg0 = null;
                           }
                           this.msgChange(_arg0);
                           reply.writeNoException();
                           return true;
                       }
                       default: {
                           return super.onTransact(code, data, reply, flags);
                       }
                   }
               }
       
               private static class Proxy implements com.open.aqrlei.ipc.aidl.IChangeListener {
                   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;
                   }
       
                   /**
                    * 此方法运行在客户端。首先会创建两个对象,输入型Parcel:"_data",输出型Parcel:"_reply",如果有返回值
                    * 会创建一个返回值对象。其次,将方法需要的参数写入_data(如果有参数的话);接着调用transact
                    * 发起RPC(远程过程调用)请求同时当前线程挂起,服务端的onTransact会被调用,直到RPC过程返回后,当前线程
                    * 继续执行,并从_reply中取出结果,如果有返回值的话,赋值给返回值对象。然后_data,_reply调用recycle
                    * 最后如果有返回值的话,返回返回值
                    *
                    */
                   @Override
                   public void msgChange(com.open.aqrlei.ipc.Info info) throws android.os.RemoteException {
                       //输入型Parcel
                       android.os.Parcel _data = android.os.Parcel.obtain();
                       //输出型Parcel
                       android.os.Parcel _reply = android.os.Parcel.obtain();
                       try {
                           _data.writeInterfaceToken(DESCRIPTOR);
                           if ((info != null)) {
                               _data.writeInt(1);
                               info.writeToParcel(_data, 0);
                           } else {
                               _data.writeInt(0);
                           }
                           mRemote.transact(Stub.TRANSACTION_msgChange, _data, _reply, 0);
                           _reply.readException();
                       } finally {
                           _reply.recycle();
                           _data.recycle();
                       }
                   }
               }
       
               static final int TRANSACTION_msgChange = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
           }
       
           /**
            * Demonstrates some basic types that you can use as parameters
            * and return values in AIDL.
            */
           public void msgChange(com.open.aqrlei.ipc.Info info) throws android.os.RemoteException;
       }
          
    
    • Binder工作机制

      Binder工作机制
    • Binder死亡代理(linkToDeath(),unLinkToDeath())

       private val mServiceConn =  object : ServiceConnection {
           override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
               mBinder = IBinderPool.Stub.asInterface(service)
               //设置死亡监听
               service?.linkToDeath(mDeathRecipient,0)
           }
      
           override fun onServiceDisconnected(name: ComponentName?) { }
       }
       private val mDeathRecipient = object : IBinder.DeathRecipient {
           /**
            * 远程服务端由于某种原因终止,此时Binder"死亡",当Binder死亡时,
            * 会回调此方法,在此处调用unlinkToDeath且将Binder置为NULL,
            * 并重新绑定服务
            * */
           override fun binderDied() {
               mBinder?.asBinder()?.unlinkToDeath(this, 0)
               mBinder = null
               //TODO bindService() 重新绑定远程服务
           }
       }   
      
      

    IPC方式

    Bundle

    Bundle 结合 Intent一起使用,一般用于四大组件(Activity、Service、Broadcast)的进程间的通信
    
    • 源码分析
      NOTE:
      1. Bundle继承BaseBundle类,实现了序列化Parcelable接口
      2. 在putXxx和getXxx的时候,第一步都要先调用unparcel方法,主要是对Parcel mParcelledData进行操作,然后再从map中获取数据
      3. Bundle中数据都存储在ArrayMap<String, Object> mMap中,如果mParcelledData不为null的时候, mMap就是null,数据存储为包含Bundle的Parcel。当数据unparcelled,mParcelledData置为null, map中存储数据
       public void putInt(@Nullable String key, int value) {
           unparcel();
           mMap.put(key, value);
       }  
        
       void unparcel() {
           synchronized (this) {
               final Parcel source = mParcelledData;
               // 如果不为null,说明数据都存在一个包含Bundle的Parcel即mParcelledData中,此时map为null
               // 就要根据mParcelledData的情况创建(如果mMap为null的话)或更新ArrayMap,并根据mParcelledData写入内容
               if (source != null) {
                   initializeFromParcelLocked(source, /*recycleParcel=*/ true);
               } else {
                   if (DEBUG) {
                       Log.d(TAG, "unparcel "
                               + Integer.toHexString(System.identityHashCode(this))
                               + ": no parcelled data");
                   }
               }
           }
       }
            
        public int getInt(String key) {
             unparcel();
             return getInt(key, 0);
         }
      
        public int getInt(String key, int defaultValue) {
             unparcel();
             Object o = mMap.get(key);
             if (o == null) {
                 return defaultValue;
             }
             try {
                 return (Integer) o;
             } catch (ClassCastException e) {
                 typeWarning(key, o, "Integer", defaultValue, e);
                 return defaultValue;
             }
        }
      

    文件共享

    NOTE:

    1. 通过读/写磁盘中的同一个文件实现进程间的数据交换
    2. 由于Linux系统并发读写文件可以没有限制的进行,不适合并发的情景
    3. SharedPreference虽然数据也是存在磁盘中的文件里,但是系统利用Map<String, Object> mMap在内存中进行了缓存,这一点会导致问题
     object FileStreamUtil {
      
       fun getObjectFile(context: Context) = getCacheFile(context, "object_test")
       fun getCacheFile(context: Context, uniqueName: String = "ipc_test.text"): File? {
           val cachePath =
                   if (Environment.MEDIA_MOUNTED == Environment.getExternalStorageState() || !Environment.isExternalStorageRemovable())
                       context.externalCacheDir?.path
                   else
                       context.cacheDir.path
      
           return File("$cachePath${File.separator}$uniqueName")
       }
      
       /**
        * @param file 写入内容的文件
        * @param content 要写入的字符串
        * */
       fun writeChar(file: File, content: String = "Hello IPC File"): Boolean {
           return try {
               BufferedWriter(FileWriter(file, true)).use { bWriter ->
                   bWriter.write((content))
                   bWriter.flush()
                   true
               }
           } catch (e: Exception) {
               Log.d("IOTest", e.message ?: "UnKnowError")
               false
           }
       }
      
       /**
        * @param user 要写入的可序列化对象
        * */
       fun writeObject(file: File?, user: User): Boolean {
           return try {
               ObjectOutputStream(FileOutputStream(file)).use {
                   it.writeObject(user)
                   it.flush()
                   true
               }
      
           } catch (e: Exception) {
               false
           }
       }
      
       /**
        * 读取写入文件的序列化对象
        * */
       fun readObject(file: File?, action: (User?) -> Unit) {
           if (file == null) {
               return
           }
           try {
               ObjectInputStream(FileInputStream(file)).use {
                   val user = it.readObject() as? User
                   action(user)
               }
           } catch (e: Exception) {
               action(null)
           }
       }
      
       /**
        * 读取写入文件的字符
        * */
       fun readChar(file: File, action: (String) -> Unit) {
           try {
               BufferedReader(FileReader(file)).use { bReader ->
                   val str = StringBuffer()
                   var buffer = -1
                   while (buffer.let {
                               buffer = bReader.read()
                               buffer
                           } != -1) {
                       str.append(buffer.toChar().toString())
                   }
                   action(str.toString())
               }
           } catch (e: Exception) {
               action(e.message ?: "UnKnowError")
           }
       }
     }
    

    Messenger

    NOTE:
    1. Messenger是基于Binder的,底层实现也是AIDL
    2. Messenger同样实现了Parcelable接口

    • 使用
      • 客户端

        // 在ServiceConnection#onServiceConnected里面获取到Binder并创建Messenger
        clientMessengerHandler.service = Messenger(it.queryBinder(IPCService.MESSENGER_BINDER_CODE)) 
        
        class ClientMessengerHandler(private val activity: WeakReference<IPCActivity>) : Handler(Looper.getMainLooper()) {
            var service: Messenger? = null
            override fun handleMessage(msg: Message?) {
                when (msg?.what) {
                    RECEIVE_FROM_SERVICE_CODE_INIT -> {
                        //将客户端的Messenger通过服务端的Messenger传送给服务端
                        service?.send( Message.obtain(null, IPCService.RECEIVE_FROM_CLIENT_CODE_INIT).apply {
                            replyTo = Messenger(clientMessengerHandler)
                             })
                    }
                   ...
                }
                super.handleMessage(msg)
            }
        }
        
      • 服务端

           MESSENGER_BINDER_CODE -> { // Binder 连接池,选用Messenger
        
             // 运行在Binder线程池中
             // 此处必须加上Looper.getMainLooper()
             serviceMessengerHandler = object : Handler(Looper.getMainLooper()) {
                   override fun handleMessage(msg: Message?) {
                       when (msg?.what) {
                           RECEIVE_FROM_CLIENT_CODE_INIT -> { //初次信息传递
        
                               if (client != msg.replyTo) {// 获取客户端返回的Messenger,用于之后两端通信
                                    client = msg.replyTo
                                }
                                  
                                   //通知客户端,首次消息接收成功
                               client?.send(Message.obtain(null, IPCActivity.RECEIVE_FROM_SERVICE_CODE_INIT))   
                            }
                           
                               ...
        
                           else -> {
                               super.handleMessage(msg)
                           }
                         }
                    }
               }
                //返回binder给客户端
               Messenger(serviceMessengerHandler).binder
            }
        
    • 源码
      Messenger 中
       public Messenger(Handler target) {
           mTarget = target.getIMessenger();
       }
       public Messenger(IBinder target) {
         mTarget = IMessenger.Stub.asInterface(target);
       }
       public void send(Message message) throws RemoteException {
         mTarget.send(message);
       }
      Handler中
       final IMessenger getIMessenger() {
         synchronized (mQueue) {
             if (mMessenger != null) {
                 return mMessenger;
             }
             mMessenger = new MessengerImpl();
             return mMessenger;
         }
       }
       private final class MessengerImpl extends IMessenger.Stub {
         public void send(Message msg) {
             msg.sendingUid = Binder.getCallingUid();
             Handler.this.sendMessage(msg);
         }
       }
      
      IMessenger.aidl中
      package android.os;
      
      import android.os.Message;
      
      /** @hide */
      oneway interface IMessenger {
         void send(in Message msg);
      } 
      
      

    AIDL

    • 支持的数据类型

      类型 说明
      基本数据类型 int, char,boolean,double,float等
      String和CharSequence
      List 只支持ArrayList传输,但是如果List是返回类型,return了一个非ArrayList的数据,Binder会根据List的规范生成一个ArrayList返回
      Map 只支持HashMap
      Parcelable 支持所有实现了Parcelable接口的类,自定义的Parcelable详情(下文)
      AIDL 所用AIDL接口,自定义的AIDL详情(下文)
    • 实现

      • 使用自定义Parcelable作为传递的数据类型

        1. 用于AIDL的Parcelable实现类必须与对应的AIDL文件在同一个包下(Parcelable实现见基础部分)
        2. 使用自定义的Parcelable,要据此创建一个AIDL
           //import 是必须要有的
          Info.aidl
           package com.open.aqrlei.ipc;
           import com.open.aqrlei.ipc.Info;
          
           parcelable Info;
          
          
          IChangeListener.aidl
           package com.open.aqrlei.ipc;
           import com.open.aqrlei.ipc.Info;
          
          
           interface IChangeListener {
               void msgChange(in Info info);
           }
          
      • 使用自定义的AIDL作为传递的数据类型,import必须要有

         package com.open.aqrlei.ipc;
         import com.open.aqrlei.ipc.IChangeListener;
        
         interface IListenerManager {
        
             void registerChangeListener(in IChangeListener listener);
        
             void unregisterChangeListener(in IChangeListener listener);
         }
        
        
      • RemoteCallbackList(使用,源码分析)
        NOTE:

        1. 用与对回调方法的管理,由于是跨进程通信,经过反序列化后,回调方法的对象与序列化前的对象实际不是同一个,这样就造成不能够简单的注册和注销回调方法。而使用RemoteCallbackList能解决这个问题。
        2. 内部实现了线程同步
        3. Binder死亡后,能自动解除Binder所对应的回调
        • 使用
        // 注册和注销
         private val mListenerManager = object : IListenerManager.Stub() {
           override fun registerChangeListener(listener: IChangeListener?) {
               listenerList.register(listener)
               sendMsgChange(Info("receive from service", 0))
           }
        
           override fun unregisterChangeListener(listener: IChangeListener?) {
             listenerList.unregister(listener)
           }
         }
        
         // 回调
         //必须先调用这个方法
         val n = listenerList.beginBroadcast()
         for (i in 0 until n) {
             listenerList.getBroadcastItem(0).msgChange(info)
         }
        
        
        • 源码
          NOTE:
          1. 注册的时候以底层不变的binder对象作为key保存到ArrayMap中,注销的时候同样用binder作为key从ArrayMap中移除。
          2. 使用的时候将ArrayMap中的数据添加到数组中,然后再从数组中获取对象进行回调的执行。
          3. 内部使用synchronized关键字实现了线程同步
          4. 在注册时候使用了linkToDeath() 关联了死亡代理 IBinder.DeathRecipient,在触发死亡代理的时候,移除相关的回调对象。在注销的时候unlinkToDeath()
         注册和注销
          public boolean register(E callback, Object cookie) {
          synchronized (mCallbacks) {//同步代码块
              if (mKilled) {
                  return false;
              }
              logExcessiveCallbacks();
              IBinder binder = callback.asBinder();
              try {
                  Callback cb = new Callback(callback, cookie);
                  // 关联到IBinder.DeathRecipient接口,Binder死亡后,移除此回调
                  binder.linkToDeath(cb, 0);
                  //序列化和反序列化后,底层binder对象是同一个,以它作为key
                  mCallbacks.put(binder, cb);
                  return true;
              } catch (RemoteException e) {
                  return false;
              }
            }
          }
          public boolean unregister(E callback) {
          synchronized (mCallbacks) {
              Callback cb = mCallbacks.remove(callback.asBinder());
              if (cb != null) {
                  cb.mCallback.asBinder().unlinkToDeath(cb, 0);
                  return true;
              }
              return false;
           }
          }
        广播
          public int beginBroadcast() {
            synchronized (mCallbacks) {
              if (mBroadcastCount > 0) {
                  throw new IllegalStateException(
                          "beginBroadcast() called while already in a broadcast");
              }
              
              final int N = mBroadcastCount = mCallbacks.size();
              if (N <= 0) {
                  return 0;
              }
              Object[] active = mActiveBroadcast;
              if (active == null || active.length < N) {
                  mActiveBroadcast = active = new Object[N];
              }
              for (int i=0; i<N; i++) {
                  //将ArrayMap中的回调添加到数组active(mActiveBroadcast中)
                  active[i] = mCallbacks.valueAt(i);
              }
              return N;
            }
          } 
        
          public E getBroadcastItem(int index) {
              //从数据mACtiveBroadcast中获取注册的回调
              return ((Callback)mActiveBroadcast[index]).mCallback;
          }
          
          public void finishBroadcast() {
            synchronized (mCallbacks) {
              if (mBroadcastCount < 0) {
                  throw new IllegalStateException(
                          "finishBroadcast() called outside of a broadcast");
              }
        
              Object[] active = mActiveBroadcast;
              if (active != null) {
                  final int N = mBroadcastCount;
                  for (int i=0; i<N; i++) {
                      //将active(mActiveBroadcast)中的数据置为null
                      active[i] = null;
                  }
              }
        
              mBroadcastCount = -1;
            }
          }
        
        
      • 连接权限验证 (表格中的方式和地方无强制关联)

      验证权限的方式 验证权限的地方
      使用自定义Permission Service#onBind方法中,不通过则返回null
      使用包名等(通过Uid获取包名) 实现AIDL的服务端调用的onTransact ,不通过则返回false
       //自定义Permission,位于AndroidManifest.xml
       <permission android:name="com.aqrlei.permission.IPC_AIDL" />
       //示例 
       override fun onBind(intent: Intent?): IBinder? {
           val check = checkCallingOrSelfPermission("com.aqrlei.permission.PROVIDER")
           return if (check == PackageManager.PERMISSION_DENIED) {
               null
           } else {
               mIBinderPool
           }
       }
      
      • 使用示例
        //服务端
         private val mListener = object:IChangeListener.Stub(){
             override fun msgChange(info: Info?) {
                  //method code
             }
         }
         override fun onBind(intent: Intent?): IBinder? {
             // 在onBind中返回
             return mListener
         }
        //客户端
          private var mListener:IChangeListener?= null
          //在ServiceConnction#onServiceConnected
          mListener = IChangeListener.Stub.asInterface(service)  
          ...
          //接下来就可以通过mListener通信了
        

    ContentProvider

    NOTE:
    1. ContentProvider是基于Binder实现的
    2. 客户端的是ContentProviderNative#ContentProviderProxy,服务端的是ContentProvider#Transport

    • 自定义ContentProvider (Sqlite为例)

        class OrderProvider : ContentProvider() {
        companion object {
            //必须和AndroidManifest.xml中配置的一样,这是ContentProvider的唯一标识
            private const val AUTHORITY = "aqrlei.OrderProvider"
      
            val ORDER_URL = Uri.parse("content://$AUTHORITY/order")
            private const val ORDER_CODE = 0X01
            private val mMatcher = UriMatcher(UriMatcher.NO_MATCH).apply {
                addURI(AUTHORITY, "order", ORDER_CODE)
            }
        }
      
        private lateinit var dataBaseOperator: DatabaseOperator
      
        override fun insert(uri: Uri, values: ContentValues?): Uri? {
            dataBaseOperator.insert(false)
            return uri
        }
      
        override fun query(uri: Uri, projection: Array<String>?, selection: String?, selectionArgs: Array<String>?, sortOrder: String?): Cursor? {
            return dataBaseOperator.query()
        }
      
        override fun onCreate(): Boolean {
            DatabaseOperator.init(context!!)
            dataBaseOperator = DatabaseOperator.getInstance()
            return true
        }
      
        override fun update(uri: Uri, values: ContentValues?, selection: String?, selectionArgs: Array<String>?): Int {
            return dataBaseOperator.update(false)
        }
      
        override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?): Int {
            return dataBaseOperator.delete(false)
        }
      
        override fun getType(uri: Uri): String? {
            return null
        }
      
      }
      
      
      1. 继承ContentProvider,实现方法
      方法 说明
      onCreate 可以作数据库的初始化操作
      insert 插入数据,返回Uri对象
      update 更新数据,返回影响的行数
      delete 删除数据,返回影响的行数
      query 返回Cursor对象
      getType 返回MIME type,单条数据以vnd.android.cursor.item 开头 ,多条数据以 vnd.android.cursor.dir/ 开头.; 或者是null
      call 实现自定义的数据访问操作
      1. 在AndroidManifest.xml中配置
         <provider
            android:name=".contentprovider.OrderProvider" //类名
            android:authorities="aqrlei.OrderProvider" //ContentProvider 的唯一标识
            android:process=":remote" // 指定进程名
            android:permission="com.aqrlei.permission.PROVIDER" // 自定义使用权限(读写权限,也可以分别指定读写权限)
             />
        
        
      2. 使用
          // ORDER_URL中包含authorities,根据这个ContentProvider唯一标识找到对应的ContentProvider
          contentResolver.query(OrderProvider.ORDER_URL, null, null, null, null)
        
    • 分析
      NOTE(可以根据以下所列查看源码):

      1. 获取contentResolver, ContextImpl#ApplicationContentResolver
      2. 获取ContentProvider的顺序为 ApplicationContentResolver#acquireProvider -> ActivityThread#acquireProvider -> ContentProviderHolder#provider
      // ContentProviderHolder
         private ContentProviderHolder(Parcel source) {
           info = ProviderInfo.CREATOR.createFromParcel(source);
           provider = ContentProviderNative.asInterface(
                   source.readStrongBinder());
           connection = source.readStrongBinder();
           noReleaseNeeded = source.readInt() != 0;
        }  
      
      //ContentProviderNative
        static public IContentProvider asInterface(IBinder obj){
           if (obj == null) {
               return null;
           }
           IContentProvider in =
               (IContentProvider)obj.queryLocalInterface(descriptor);
           if (in != null) {
               return in;
           }
      
           return new ContentProviderProxy(obj);
       }
      
      
      1. ContentProviderNative#ContentProviderProxy是客户端通过ApplicationContentResolver获取的并运行在客户端的
      2. ContentProvider#Transport是运行在服务端的

    Socket

    NOTE: 使用Socket需要使用网络相关权限

      <uses-permission android:name="android.permission.INTERNET" />
      <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    
    • 服务端
         private inner class TcpServer : Runnable {
           private var client: Socket? = null
           override fun run() {
               val serverSocket: ServerSocket
               try {
                   //监听 本地端口
                   serverSocket = ServerSocket(9999)
                 } catch (e: IOException) {
                   e.printStackTrace()
                   return
                 }
               while (!serviceDestroyed) {//服务未停止
                   try {
                       Log.d("Socket", "TcpServer Run")
                       client = serverSocket.accept()
                       thread {
                           try {
                               //客户端连接上了
                               responseClient(client!!)
                           } catch (e: IOException) {
                               e.printStackTrace()
                               Log.d("Socket", "TcpServer Thread Run onError ${e.message}")
                           }
                       }
                   } catch (e: IOException) {
                       Log.d("Socket", "TcpServer Run OnError ${e.message}")
                       e.printStackTrace()
                   }
               }
               client?.close()
               Log.d("Socket", "TcpServer Client close $serviceDestroyed")
           }
      
           @Throws(IOException::class)
           private fun responseClient(client: Socket) {
               val inReader: BufferedReader? = BufferedReader(InputStreamReader(client.getInputStream()))
               val outWriter: PrintWriter? = PrintWriter(BufferedWriter(OutputStreamWriter(client.getOutputStream())), true)
               Log.d("Socket", "TcpServer response $serviceDestroyed")
               while (!serviceDestroyed) {
                   Log.d("Socket", "TcpServer response before $serviceDestroyed")
                   //读取客户端发来的信息
                   val str = inReader?.readLine()
                   if (str != null) {
                       Log.d("Socket", "TcpServer response $str")
                       val time = SimpleDateFormat("hh:mm:ss.SSS", Locale.ROOT).format(System.currentTimeMillis())
                       //给客户端写信息
                       outWriter?.println("通过Socket回传:$str-$time")
                       sendMsgChange(Info("AIDL回传:$str-$time", -1))
                       /*outWriter?.close()
                       inReader?.close()*/
                   }
               }
               Log.d("Socket", "TcpServer response after $serviceDestroyed")
           }
        }
      
      
    • 客户端
         private var mClientSocket: Socket? = null
         private var mPrintWriter: PrintWriter? = null
         private fun connectTcpServer() {
             var socket: Socket? = null
             while (socket == null) {  // 连接失败的话,每隔1秒重连一次
                 try {
                     //连接到本地端口
                     socket = Socket("localhost", 9999)
                     mClientSocket = socket
                     // 用于向服务端写入数据
                     mPrintWriter = PrintWriter(BufferedWriter(OutputStreamWriter(socket.getOutputStream())), true)
                     //通过Handler通知Socket连接成功
                     clientMessengerHandler.sendEmptyMessage(LOCAL_SOCKET_CONNECTED)
                 } catch (e: IOException) {
                     SystemClock.sleep(1000)
                 }
             }
             try {
                 //获取服务端发送的数据
                 BufferedReader(InputStreamReader(socket.getInputStream())).use {
                     while (!this.isFinishing) {
                         var msg = it.readLine()
                         if (!msg.isNullOrEmpty()) {
                             msg = "$msg-$time"
                             //通过Handler将数据发送到UI线程处理
                             clientMessengerHandler.obtainMessage(LOCAL_SOCKET_SEND_MESSAGE, msg).sendToTarget()
                         }
                     }
                 }
             } catch (e: IOException) {
                 e.printStackTrace()
             }
         }
          //向服务端发送消息
         mPrintWriter?.println("Hello Socket:$time")
      
         // onDestroy的时候处理socket相关
         override fun onDestroy() {
           if (mClientSocket != null) {
               try {
                   mPrintWriter?.close()
                   mClientSocket?.shutdownInput()
                   mClientSocket?.close()
               } catch (e: IOException) {
                   e.printStackTrace()
               }
           }
           super.onDestroy()
       }
      

    Binder连接池

    NOTE:AIDL的实现方式,主要原理是:
    1. 客户端发送对应的Code;
    2. 服务端根据Code返回对应的IBinder;
    3. 客户端再根据IBinder将之转换成对应的AIDL接口.

       IBinderPool.aidl
       package com.open.aqrlei.ipc;
    
       interface IBinderPool {
            IBinder queryBinder(int binderCode);
       }
    
       //#服务端
       private val mIBinderPool = object : IBinderPool.Stub() {
           @Throws(RemoteException::class)
           override fun queryBinder(binderCode: Int): IBinder {
               return when (binderCode) {
                  // method code
               }
           }
       }
       // #客户端-ServiceConnection#onServiceConnected
        mBinder = IBinderPool.Stub.asInterface(service)
        
        // 获取到Messenger的IBinder
        messenger = Messenger(mBinder.queryBinder(USE_MESSENGER_CODE))
    
    
    

    IPC方式适用场景(源于Android开发艺术探索)

    方式 优点 缺点 适用场景
    Bundle 简单易用 只能传输Bundle支持的数据 四大组件间的进程间通信
    文件共享 简单易用 不适合高并发,无法做到进程间实时通信 无并发,交换简单的数据,实时性不高
    Messenger 功能一般,一对多串行通信,实时通信 不能很好的处理高并发, 不支持RPC,数据通过Message传输,支持的类型有局限性 低并发的一对多通信,无RPC请求(或无需返回值的RPC)
    AIDL 功能强大,一对多并发,实时通信 使用稍微复杂,需要处理好线程同步 一对多通信且有RPC需求
    ContentProvider 数据访问方面功能强大,一对多并发数据共享,Call方法扩展其它操作 主要提供数据源的CRUD 一对多进程间数据共享
    Socket 功能强大,通过网络传输字节流,一对多并发实时通信 实现稍微繁琐,不支持RPC 网络数据交换

    资源

    Android开发艺术探索 - 任玉刚

    Android-Art-Res-Chapter_2

    IPCSample

    相关文章

      网友评论

        本文标题:Android IPC(进程间通信)

        本文链接:https://www.haomeiwen.com/subject/cqegiqtx.html