IPC 机制

848 阅读13分钟

IPC 简介

IPC 是 Inter-Process Communication 的缩写,意思是跨进程通信,是指两个进程之间进行数据交换的过程。

在 Android 中,默认情况下一个 App 只有一个进程,但是可以通过在 AndroidMenifest.xml 中给四大组件(Activity、Service、Receiver、ContentProvider)指定 android:process 属性来开启多进程。

<activity
    android:name="com.example.test.MainActivity"
    android:configChanges="orientation|screenSize">
    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
    </intent-filter>
</activity>

<activity
    android:name="com.example.test.SecondActivity"
    android:configChanges="screenLayout"
    android:process=":remote" />

<activity
    android:name="com.example.test.ThirdActivity"
    android:configChanges="screenLayout"
    android:process="com.example.test.remote"/>

上面的示例分别为 SecondActivity 和 ThirdActivity 指定了 process 属性,并且它们的属性值不同,这意味着当前应用又增加了两个新进程。假设当前应用的包名为 “com.example.test”,当 SecondActivity 启动时,系统会为它创建一个单独的进程,进程名为 “com.example.test:remote”;当 ThirdActivity 启动时,系统也会为它创建一个单独的进程,进程名为“com.example.test.remote”。同时入口 Activity 是 MainActivity,没有为它指定 process 属性,那么它运行在默认进程中,默认进程的进程名是包名。

在 Android Studio 中选择 Attach Debugger to Android Process 可以看到这3个进程:

image.png

你还可以用 shell 命令来查看进程信息,命令为:ps -A | grep com.example.test,如下图:

image.png

你有没有注意到,SecondActivity 和 ThirdActivity 的 android:process 属性分别为 “:remote” 和 “com.example.test.remote”,那么这两种方式有区别吗?其实是有区别的,区别有两方面:首先,“:” 的含义是指要在当前的进程名前面附加上当前的包名,“:” 是简写,对于SecondActivity 来说,它完整的进程名为 “com.example.test:remote”,这一点通过上图中的进程信息也能看出来,而对于 ThirdActivity 中的声明方式,它是一种完整的命名方式,不会附加包名信息;其次,进程名以 “:” 开头的进程属于当前应用的私有进程,其他应用的组件不可以和它跑在同一个进程中,而不以 “:” 开头的进程属于全局进程,其他应用通过 ShareUID 方式可以和它跑在同一个进程中。

我们知道 Android 系统会为每个应用分配一个唯一的 UID,具有相同 UID 的应用才能共享数据。这里要说明的是,两个应用通过 ShareUID 跑在同一个进程中是有要求的,需要这两个应用有相同的 ShareUID 并且签名相同才可以。在这种情况下,它们可以互相访问对方的私有数据,比如 data 目录、组件信息等,不管它们是否跑在同一个进程中。当然如果它们跑在同一个进程中,那么除了能共享 data 目录、组件信息,还可以共享内存数据,或者说它们看起来就像是一个应用的两个部分。

多进程导致的问题

这样看来开启多进程是不是很简单,直接指定 android:process 属性就行了,但是多进程会有一些其他的问题,比如新建了一个名为 UserManager 的类,里面有一个静态成员变量 sUserId ,如下所示:

public class UserManager{
    public static int sUserId = 1;
}

如果我们在 MainActivity 中把 sUserId 赋值为 2,然后在 SecondActivity 中打印 sUserId 的值,发现还是 1。上述问题出现的原因是 SecondActivity 运行在一个单独的进程中,我们知道 Android 为每一个应用分配了一个独立的虚拟机,或者说为每个进程都分配一个独立的虚拟机,不同的虚拟机在内存分配上有不同的地址空间,这就导致在不同的虚拟机中访问同一个类的对象会产生多份副本。也就是说两个进程中都存在 UserManager 类,并且这两个类互不干扰。

一般来说,使用多进程会造成如下几方面的问题:

  1. 静态成员和单例模式完全失效。
  2. 线程同步机制完全失效。
  3. SharedPreferences 的可靠性下降。
  4. Application 会多次创建。

第 1 和第 2 个问题很好理解,第 3 个问题是因为 SharedPreferences 不支持两个进程同时去执行写操作,否则会导致一定几率的数据丢失,这是因为 SharedPreferences 底层是通过读/写 XML 文件来实现的,并发写显然是可能出问题的,甚至并发读/写都有可能出问题。第4个问题也是显而易见的,当一个组件跑在一个新的进程中的时候,由于系统要在创建新的进程同时分配独立的虚拟机,所以这个过程其实就是启动一个应用的过程。因此,相当于系统又把这个应用重新启动了一遍,既然重新启动了,那么自然会创建新的 Application。这个问题其实可以这么理解,运行在同一个进程中的组件是属于同一个虚拟机和同一个 Application 的,同理,运行在不同进程中的组件是属于两个不同的虚拟机和 Application 的。为了更加清晰地展示这一点,下面我们来做一个测试,在 Application 的 onCreate() 方法中打印出当前进程的名字,代码如下:

public class MyApplication extends Application {

    private static final String TAG ="MyApplication";

    @Override
    public void onCreate(){
        super.onCreate();
        String processName = MyUtils.getProcessName(getApplicationContext(), android.os.Process.myPid());
        Log.d(TAG, "application start, process name:"+ processName);
    }
}

public class MyUtils {

    public static String getProcessName(Context cotext, int pid){
        ActivityManager activityManager = (ActivityManager) cotext.getSystemService(Context.ACTIVITY_SERVICE);
        for (ActivityManager.RunningAppProcessInfo appProcessInfo : activityManager.getRunningAppProcesses()) {
            if (appProcessInfo.pid == pid) {
                return appProcessInfo.processName;
            }
        }
        return "";
    }
}

顺序启动 MainActivity、SecondActivity、ThirdActivity,Log 打印如下:

MyApplication  com.example.test  D  application start, process name:com.example.test
MyApplication  com.example.test  D  application start, process name:com.example.test:remote
MyApplication  com.example.test  D  application start, process name:com.example.test.remote

可以看到,Application的 onCreate() 方法执行了三次并打印出了三次进程名,这也就证实了在多进程模式中,不同进程的组件的确会拥有独立的虚拟机、Application 以及内存空间,这会给实际的开发带来很多困扰,是尤其需要注意的。

Binder

从 IPC 的角度来说,Binder 是 Android 中的一种跨进程通信方式,Binder 还可以理解为一种虚拟的物理设备,它的设备驱动是/dev/binder,该通信方式在 Linux 中没有;从 Android Framework 的角度来说,Binder 是 ServiceManager 连接各种 Manager (ActivityManager、WindowManager 等等)和相应 ManagerService 的桥梁;从 Android 应用层来说,Binder 是客户端和服务端进行通信的媒介,当 bindService 的时候,服务端会返回一个包含了服务端业务调用的 Binder 对象,通过这个 Binder 对象,客户端就可以获取服务端提供的服务或者数据,这里的服务包括普通服务和基于 AIDL 的服务。

为了分析 Binder 的工作机制,我们新建一个 AIDL 示例。

在 main 目录右键 New > AIDL > AIDL Folder,操作完后 main 目录下会自动新建一个 aidl 目录,包名为 com.example.binderclient。在这里添加 2 个文件:Apple.aidl 和 IAppleManager.aidl,代码如下:

// Apple.aidl
package com.example.binderclient;

parcelable Apple;
// IAppleManager.aidl
package com.example.binderclient;

import com.example.binderclient.Apple;

interface IAppleManager {
    List<Apple> getAppleList();
    void addApple(in Apple apple);
}

在普通目录下添加 Apple.java 类,代码如下:

// Apple.java
package com.example.binderclient;

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

import androidx.annotation.NonNull;

public class Apple implements Parcelable {
    private String name;
    private String loc;

    public Apple(String name, String loc) {
        this.name = name;
        this.loc = loc;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(@NonNull Parcel dest, int flags) {
        dest.writeString(name);
        dest.writeString(loc);
    }

    public static final Creator<Apple> CREATOR = new Creator<Apple>() {
        @Override
        public Apple createFromParcel(Parcel in) {
            return new Apple(in);
        }

        @Override
        public Apple[] newArray(int size) {
            return new Apple[size];
        }
    };

    protected Apple(Parcel in) {
        name = in.readString();
        loc = in.readString();
    }

}

上面三个文件中,Apple.java 是一个表示苹果信息的类,它实现了 Parcelable 接口。Apple.aidl 是 Apple 类在 AIDL 中的声明。IAppleManager.aidl 是我们定义的一个接口,里面有两个方法:getAppleList() 和 addApple(),其中 getAppleList() 用于从远程服务端获取苹果列表,而 addApple() 用于往苹果列表中添加一个苹果。可以看到,尽管 Apple 类已经和 IAppleManager 位于相同的包中,但是在 IAppleManager 中仍然要导入 Apple 类,这就是 AIDL 的特殊之处。下面我们先看一下系统为 IAppleManager.aidl 生产的 Binder 类,make 项目后,在 build 目录下可以找到该类: IAppleManager.java:

image.png

下面我们根据这个系统生成的 Binder 类来分析 Binder 的工作原理。

在 Binder 服务端,我们需要新建 IAppleManager.Stub 实例,实现里面的方法,并在 onBind() 方法中返回该实例,代码如下:

public class AppleService extends Service {
    ...
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    private final IAppleManager.Stub mBinder = new IAppleManager.Stub() {
        @Override
        public List<Apple> getAppleList() throws RemoteException {
            return mAppleList;
        }

        @Override
        public void addApple(Apple apple) throws RemoteException {
            if(!mAppleList.contains(apple)){
                mAppleList.add(apple);
            }
        }
    };
}

其中的 Stub 是 IAppleManager 的一个抽象静态内部类,继承自 Binder 并实现了 IAppleManager 接口,代码如下:

public interface IAppleManager extends android.os.IInterface
{    
    public static abstract class Stub extends android.os.Binder implements com.example.binderserver.IAppleManager
    {
        // 构造函数,调用 Binder 的 attachInterface() 方法
        public Stub()
        {
          this.attachInterface(this, DESCRIPTOR);
        }
        
        // 将 IBinder 对象转成  com.example.binderserver.IAppleManager 接口,
        // 如果需要会生成一个代理对象
        public static com.example.binderserver.IAppleManager asInterface(android.os.IBinder obj)
        {
            if ((obj==null)) {
              return null;
            }
            // 使用 queryLocalInterface() 方法获取 IBinder 接口的本地实现
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin!=null)&&(iin instanceof com.example.binderserver.IAppleManager))) {
              return ((com.example.binderserver.IAppleManager)iin);
            }
            // 返回 IAppleManager.Stub.Proxy 对象
            return new com.example.binderserver.IAppleManager.Stub.Proxy(obj);
        }
        
        @Override 
        public android.os.IBinder asBinder()
        {
            // 此方法用于返回当前 Binder 对象
            return this;
        }
        
        @Override 
        public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
        {
            // 这里后面再分析
            ...
        }
        
        static final int TRANSACTION_getAppleList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        
        static final int TRANSACTION_addApple = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    }

    // Binder 的唯一标识,一般用当前 Binder 的类名表示
    public static final java.lang.String DESCRIPTOR = "com.example.binderserver.IAppleManager";  
    
    public java.util.List<com.example.binderserver.Apple> getAppleList() throws android.os.RemoteException;
    
    public void addApple(com.example.binderserver.Apple apple) throws android.os.RemoteException;
}

客户端需要调用 bindService() 方法绑定服务端的 Service,代码如下:

public class MainActivity extends AppCompatActivity {

    private IAppleManager mAppleManager;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...
    }

    ServiceConnection mServiceConn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.e("client", "onServiceConnected");
            mAppleManager = IAppleManager.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.e("client", "onServiceDisconnected");
            mAppleManager = null;
        }
    };

    @Override
    public void onClick(View v) {
        if(v.getId() == R.id.btn_bind){
            ...
            // 绑定服务
            boolean result = bindService(intent, mServiceConn, Context.BIND_AUTO_CREATE);
            ...
        }else if (v.getId() == R.id.btn_add) {
            // 添加苹果
            ...
            if(mAppleManager != null){
                mAppleManager.addApple(new Apple("红星", "山东"));
            }    
            ...
        }else if(v.getId() == R.id.btn_show) {
            // 获取苹果列表
            if(mAppleManager != null){
                List<Apple> appleList = mAppleManager.getAppleList();
                ...
            }
        }
    }
}

在 ServiceConnection 的 onServiceConnected() 方法中会拿到服务端的 Binder 对象,并调用 IAppleManager.Stub 的 asInterface() 方法将服务端的 Binder 对象转换成客户端所需的 AIDL 接口类型的对象。这个转换过程是区分进程的,如果客户端和服务端位于同一进程,那么此方法返回的就是服务端的 Stub 对象本身,否则返回的是系统封装后的 IAppleManager.Stub.Proxy 对象。这里我们只分析跨进程的调用过程。

其中 Proxy 是 IAppleManager.Stub 的内部类,代码如下:

public interface IAppleManager extends android.os.IInterface
{    
    public static abstract class Stub extends android.os.Binder implements com.example.binderserver.IAppleManager
    {
        private static class Proxy implements com.example.binderserver.IAppleManager
        {
            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<com.example.binderserver.Apple> getAppleList() throws android.os.RemoteException
            {
                  // 创建输入型 Parcel 对象 _data  
                  android.os.Parcel _data = android.os.Parcel.obtain();
                  // 创建输出型 Parcel 对象 _reply
                  android.os.Parcel _reply = android.os.Parcel.obtain();
                  // 返回值
                  java.util.List<com.example.binderserver.Apple> _result;
                  try {
                    // 将 IBinder Interface Token写入 _data 
                    _data.writeInterfaceToken(DESCRIPTOR);
                    // 调用 transact() 方法来发起 RPC 请求,同时当前线程会挂起,
                    // 然后服务端的 onTransact() 方法会被调用,直到 RPC 过程返回后,当前线程继续执行
                    boolean _status = mRemote.transact(Stub.TRANSACTION_getAppleList, _data, _reply, 0);
                    _reply.readException();
                    // 从 _reply 中读取 RPC 过程的返回结果,赋值给 _result
                    _result = _reply.createTypedArrayList(com.example.binderserver.Apple.CREATOR);
                  }
                  finally {
                    _reply.recycle();
                    _data.recycle();
                  }
                  return _result;
          }
          
          @Override 
          public void addApple(com.example.binderserver.Apple apple) throws android.os.RemoteException
          {
                  android.os.Parcel _data = android.os.Parcel.obtain();
                  android.os.Parcel _reply = android.os.Parcel.obtain();
                  try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _Parcel.writeTypedObject(_data, apple, 0);
                    boolean _status = mRemote.transact(Stub.TRANSACTION_addApple, _data, _reply, 0);
                    _reply.readException();
                  }
                  finally {
                    _reply.recycle();
                    _data.recycle();
                  }
          }
        }
    }
}    

Proxy 也实现了 IAppleManager 接口,并且 Proxy 继承了 Binder 类,在客户端 获取苹果列表 和 添加苹果 会分别调用 Proxy 的 getAppleList() 和 addApple() 方法。

getAppleList() 方法运行在客户端,当客户端远程调用此方法时,它的内部实现是这样的:首先创建该方法所需要的输入型 Parcel 对象 _data,输出型 Parcel 对象 _reply 和返回值 _result,然后把 IBinder Interface Token 写入 _data;接着调用 IBinder 的 transact() 方法来发起 RPC(远程过程调用)请求,同时当前线程挂起;然后服务端的 onTransact() 方法会被调用,直到 RPC 过程返回后,当前线程继续执行,并从 _reply 中取出 RPC 过程的返回结果,赋值给 _result;最后返回 _result 中的数据。addApple() 方法的执行过程和 getAppleList() 方法类似,就不分析了。

onTransact() 方法运行在服务端中的 Binder 线程池中,代码如下:

public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
    java.lang.String descriptor = DESCRIPTOR;
    
    if (code >= android.os.IBinder.FIRST_CALL_TRANSACTION && code <= android.os.IBinder.LAST_CALL_TRANSACTION) {
          data.enforceInterface(descriptor);
    }
    
    switch (code)
    {
          case INTERFACE_TRANSACTION:
          {
                reply.writeString(descriptor);
                return true;
          }
    }
    
    switch (code)
    {
          case TRANSACTION_getAppleList:
          {
                // 调用服务端的方法
                java.util.List<com.example.binderserver.Apple> _result = this.getAppleList();
                reply.writeNoException();
                reply.writeTypedList(_result);
                break;
          }
          case TRANSACTION_addApple:
          {
                com.example.binderserver.Apple _arg0;
                _arg0 = _Parcel.readTypedObject(data, com.example.binderserver.Apple.CREATOR);
                this.addApple(_arg0);
                reply.writeNoException();
                break;
          }
          default:
          {
                return super.onTransact(code, data, reply, flags);
          }
    }
    
    return true;
}

当客户端发起跨进程请求时,远程请求会通过系统底层封装后交由此方法来处理。仔细观察可以发现,服务端的 onTransact() 方法与客户端的 transact() 方法的参数是对应的。服务端通过 code 可以确定客户端所请求的目标方法是什么,然后执行目标方法。data 是客户端传递过来的参数,当目标方法执行完毕后,就向 reply 中写入返回值(如果目标方法有返回值的话)。flags 标明是否有返回值,0为有(双向),1为没有(单向)。需要注意的是,如果此方法返回 false,那么客户端的请求会失败,因此我们可以利用这个特性来做权限验证,毕竟我们也不希望随便一个进程都能远程调用我们的服务。

有两点还是需要额外说明一下:

  • 当客户端发起远程请求时,由于当前线程会被挂起直至服务端进程返回数据,所以如果一个远程方法是很耗时的,那么不能在 UI 线程中发起此远程请求。
  • 由于服务端的 Binder 方法运行在 Binder 的线程池中,所以 Binder 方法不管是否耗时都应该采用同步的方式去实现,因为它已经运行在一个线程中了。

自己写一个Binder

其实我们完全可以不使用 AIDL 文件,自己写一个 Binder 出来,AIDL 文件的本质是系统为我们提供的一种快速实现 Binder 的工具而已。

我们先编写客户端的代码,把 IAppleManager 接口单独提取出来,代码如下:

public interface IAppleManager extends android.os.IInterface {

    java.lang.String DESCRIPTOR = "com.example.binderclient.IAppleManager";

    int TRANSACTION_getAppleList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    
    int TRANSACTION_addApple = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);

    List<Apple> getAppleList() throws android.os.RemoteException;

    void addApple(Apple apple) throws android.os.RemoteException;

}

Stub 类的 asInterface() 方法只是根据是否在同一个进程中返回不同的对象,我们可以确定是跨进程通信,那么这里可以直接去掉。我们把 Proxy 类单独提取出来作为一个单独的类,并改名为:AppleManagerImpl,代码如下:

public  class AppleManagerImpl implements IAppleManager{

    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<com.example.binderclient.Apple> getAppleList() throws android.os.RemoteException{
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        java.util.List<com.example.binderclient.Apple> _result;
        try {
            _data.writeInterfaceToken(DESCRIPTOR);
            boolean _status = mRemote.transact(TRANSACTION_getAppleList, _data, _reply, 0);
            _reply.readException();
            _result = _reply.createTypedArrayList(com.example.binderclient.Apple.CREATOR);
        }
        finally {
            _reply.recycle();
            _data.recycle();
        }
        return _result;
    }
    
    @Override
    public void addApple(com.example.binderclient.Apple apple) throws android.os.RemoteException{
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        try {
            _data.writeInterfaceToken(DESCRIPTOR);
            _Parcel.writeTypedObject(_data, apple, 0);
            boolean _status = mRemote.transact(TRANSACTION_addApple, _data, _reply, 0);
            _reply.readException();
        }
        finally {
            _reply.recycle();
            _data.recycle();
        }
    }

    static class _Parcel {
        static private <T> T readTypedObject(
                android.os.Parcel parcel,
                android.os.Parcelable.Creator<T> c) {
            if (parcel.readInt() != 0) {
                return c.createFromParcel(parcel);
            } else {
                return null;
            }
        }
        static private <T extends android.os.Parcelable> void writeTypedObject(
                android.os.Parcel parcel, T value, int parcelableFlags) {
            if (value != null) {
                parcel.writeInt(1);
                value.writeToParcel(parcel, parcelableFlags);
            } else {
                parcel.writeInt(0);
            }
        }
    }
}

这样在客户端的 onServiceConnected() 方法中直接 new AppleManagerImpl(service) 就可以了,代码如下:

ServiceConnection mServiceConn = new ServiceConnection() {

    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        mAppleManager = new AppleManagerImpl(service);
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        mAppleManager = null;
    }
};

然后一样可以在客户端调用其 addApple() 和 getAppleList() 方法。

在服务端,新建一个与客户端相同的 IAppleManager 接口,其实现类 AppleManagerImpl 与客户端不同,服务端的 AppleManagerImpl 需要继承 Binder 类,代码如下:

public abstract class AppleManagerImpl extends Binder implements IAppleManager {

    @Override
    public IBinder asBinder() {
        return this;
    }

    @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;
        if (code >= android.os.IBinder.FIRST_CALL_TRANSACTION && code <= android.os.IBinder.LAST_CALL_TRANSACTION) {
            data.enforceInterface(descriptor);
        }
        switch (code)
        {
            case INTERFACE_TRANSACTION:
            {
                reply.writeString(descriptor);
                return true;
            }
        }
        switch (code)
        {
            case TRANSACTION_getAppleList:
            {
                java.util.List<com.example.binderserver.Apple> _result = this.getAppleList();
                reply.writeNoException();
                reply.writeTypedList(_result);
                break;
            }
            case TRANSACTION_addApple:
            {
                com.example.binderserver.Apple _arg0;
                _arg0 = _Parcel.readTypedObject(data, com.example.binderserver.Apple.CREATOR);
                this.addApple(_arg0);
                reply.writeNoException();
                break;
            }
            default:
            {
                return super.onTransact(code, data, reply, flags);
            }
        }
        return true;
    }

    static class _Parcel {
        static private <T> T readTypedObject(
                android.os.Parcel parcel,
                android.os.Parcelable.Creator<T> c) {
            if (parcel.readInt() != 0) {
                return c.createFromParcel(parcel);
            } else {
                return null;
            }
        }
        static private <T extends android.os.Parcelable> void writeTypedObject(
                android.os.Parcel parcel, T value, int parcelableFlags) {
            if (value != null) {
                parcel.writeInt(1);
                value.writeToParcel(parcel, parcelableFlags);
            } else {
                parcel.writeInt(0);
            }
        }
    }
}

在服务端 new AppleManagerImpl() 就可以拿到 Binder 实例了:

private final AppleManagerImpl mBinder = new AppleManagerImpl() {

    @Override
    public List<Apple> getAppleList() throws RemoteException {
        return mAppleList;
    }

    @Override
    public void addApple(Apple apple) throws RemoteException {
        if(!mAppleList.contains(apple)){
            mAppleList.add(apple);
        }
    }
};

这样,不使用 AIDL 文件就实现了 Binder,手动去写的意义在于可以让我们更加理解 Binder 的工作原理。

Demo地址:github.com/EnzoXRay/Cu…