Android-IPC进程间通信机制

Android-IPC进程间通信机制


本文由 Luzhuo 编写,转发请保留该信息.
原文: http://blog.csdn.net/Rozol/article/details/75451825


Android除了继承Linux的进程间通信方式外, 还有自己的通信方式,如Binder.
Binder比Linux的跨进程通信,性能更高,更安全

多进程创建

进程的创建仅需在清单文件配置即可

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="me.luzhuo.ipc">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <!--
            四大组件(Activity/Service/Receiver/ContentProvider)在清单文件中指定 android:process 进程名
            android:process 进程名指定方式:
                :process_name1 : 在当前包名后面添加该进程名, 属于私有进程
                me.luzhuo.ipc2 : 完整进程名, 属于公有进程
        -->
        <activity android:name=".process.Process1Activity"
            android:process=":process_name1"/>
        <activity android:name=".process.Process2Activity"
            android:process="me.luzhuo.ipc2"/>
    </application>

</manifest>

进程间通信

Serializable

Serializable是通过序列化到文件的方式进行的,效率相比Parcelable低

public class Person implements Serializable{

    // AndroidStudio: File –> Settings –> Editor –> Inspections –> Java –> Serialization issues –> Serializable class without ‘serialVersionUID’ -> √
    // 选中实现了Serializable的类, Alt+Enter
    private static final long serialVersionUID = -8946165700470434349L;

    public String name;
    public int age;
    public String address;

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", address='" + address + '\'' +
                '}';
    }
}
Serializable + ObjectOutputStream

文件共享的方式, 将对象序列化到文件,然后从另一进程读取出来

在进程A进行序列化操作

public void serializable(View view){
    Person person = new Person();
    person.name = "luzhuo";
    person.age = 21;
    person.address = "xxx";

    try {
        ObjectOutputStream write = new ObjectOutputStream(new FileOutputStream(file));
        write.writeObject(person);
        write.close();

    } catch (IOException e) {
        e.printStackTrace();
    }
}

在进程B进行反序列化操作

public void deserializable() {
    try {
        ObjectInputStream read = new ObjectInputStream(new FileInputStream(file));
        Person person = (Person) read.readObject();
        read.close();

        Log.e(TAG, person.toString());

    } catch (IOException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e){
        e.printStackTrace();
    }
}

Parcelable

Parcelable是通过序列化到内存的方式进行的,效率相比Serializable高

public class Person implements Parcelable {

    public String name;
    public int age;
    public String address;

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", address='" + address + '\'' +
                '}';
    }

    protected Person(Parcel in) {
        name = in.readString();
        age = in.readInt();
        address = in.readString();
        // obj = in.readParcelable(Thread.currentThread().getContextClassLoader());
        // boolean = in.readInt() == 1;
    }

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

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

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

    @Override
    public void writeToParcel(Parcel parcel, int i) {
        parcel.writeString(name);
        parcel.writeInt(age);
        parcel.writeString(address);
        // parcel.writeParcelable(obj, 0); // 对象
        // parcel.writeInt(true ? 1 : 0); // boolean
    }
}
Parcelable + Bundle

Parcelable可以借助Intent和Binder进行跨进程传递
Bundle附加信息,然后通过Intent进行跨进程传递

在进程A的Bundle中添加数据,然后通过Intent传递

public void serializable(View view){
    Person person = new Person();
    person.name = "Luzhuo";
    person.age = 22;
    person.address = "luzhuo.me";

    intent = new Intent(this, RemoteParcelableActivity.class);
    Bundle bundle = new Bundle();
    bundle.putParcelable("par", person);
    // bundle.putSerializable("par", person);
    intent.putExtras(bundle);
}

在进程B中,获取Intent取出数据

public void deserializable() {
    Intent intent = getIntent();
    Person person = intent.getParcelableExtra("par");
    Log.e(TAG, person.toString());
}

Intent的大小限制

Intent是通过Binder传输数据的, 即使你的类实现了Serializable接口, 只要你没主动序列化到本地, 都是通过Binder进行传输数据的.

如果超过Binder限制将抛出此异常

Caused by: android.os.TransactionTooLargeException: data parcel size 104858164 bytes

根据 Google 的解释, 这个大小是1MB, 称为Binder事务缓冲区(Binder transaction buffer), 并且所有进程共用这块大小.
所以就算你传递数据没那么大, 缓存的事务多了照样崩.

Binder

Binder能有一对多的进行并发式实时通信,是非常理想的跨进程通信机制

当我们编写Binder的AIDL文件后,系统会帮我们生成一个Binder类

创建方法: 右键包名 -> New -> AIDL -> AIDL File
生成aidl对应的java文件: Build -> Make Project (生成的java文件在:\app\build\generated\source\aidl\debug\me\luzhuo\ipc\abc\binder)

// IBinderManager.aidl
interface IBinderManager {
    // AIDL支持的数据类型: 基本数据类型, List(ArrayList), Map(HashMap), Parcelable, AIDL
    Person getPerson();
    // 除了基本数据类型,其他类型的参数须标上方向: in(输入参数) / out(输出参数) / inout(输入输出参数)
    void setBinderUse(in Person person);
}


// 这是由系统自动生成的java类, 继承了 IInterface 接口
public interface IBinderManager extends android.os.IInterface {
    /**
     * Local-side IPC implementation stub class.
     */
	 // 声明了内部类 Stub ,继承于 Binder
    public static abstract class Stub extends android.os.Binder implements me.luzhuo.ipc.abc.binder.IBinderManager {
		// Binder 类的唯一标识
        private static final java.lang.String DESCRIPTOR = "me.luzhuo.ipc.abc.binder.IBinderManager";

        /**
         * Construct the stub at attach it to the interface.
         */
        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }

        /**
         * Cast an IBinder object into an me.luzhuo.ipc.abc.binder.IBinderManager interface,
         * generating a proxy if needed.
         */
		 // 将服务端的Binder对象转为客户端所需的AIDL接口对象
        public static me.luzhuo.ipc.abc.binder.IBinderManager asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof me.luzhuo.ipc.abc.binder.IBinderManager))) {
				// 如果客户端和服务端在同一进程中,则返回 IBinderManager 自身
                return ((me.luzhuo.ipc.abc.binder.IBinderManager) iin);
            }
			// 如果客户端和服务端不在同一进程中,则返回 IBinderManager.Stub.Proxy 对象
            return new me.luzhuo.ipc.abc.binder.IBinderManager.Stub.Proxy(obj);
        }

		// 返回当前Binder对象
        @Override
        public android.os.IBinder asBinder() {
            return this;
        }

		// 该方法运行于服务端的Binder线程池中, 当客户端发起跨进程请求时,系统会将其交给此方法处理
        @Override
        public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
            switch (code) { // 服务端通过code来区分客户端发起的请求方法是哪个
                case INTERFACE_TRANSACTION: {
                    reply.writeString(DESCRIPTOR);
                    return true;
                }
                case TRANSACTION_getPerson: {
                    data.enforceInterface(DESCRIPTOR);
                    me.luzhuo.ipc.abc.binder.Person _result = this.getPerson();
                    reply.writeNoException();
                    if ((_result != null)) {
                        reply.writeInt(1);
                        _result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); // 如果有返回值,则向 _result 写入返回值
                    } else {
                        reply.writeInt(0);
                    }
                    return true; // 返回true为请求成功,false为请求失败
                }
                case TRANSACTION_setBinderUse: {
                    data.enforceInterface(DESCRIPTOR);
                    me.luzhuo.ipc.abc.binder.Person _arg0;
                    if ((0 != data.readInt())) { // 如果目标方法有参数的话,则取出目标方法所需的参数
                        _arg0 = me.luzhuo.ipc.abc.binder.Person.CREATOR.createFromParcel(data);
                    } else {
                        _arg0 = null;
                    }
                    this.setBinderUse(_arg0); // (取出参数后,) 然后执行目标方法
                    reply.writeNoException();
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }

		// 内部代理类 Proxy
        private static class Proxy implements me.luzhuo.ipc.abc.binder.IBinderManager {
            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 me.luzhuo.ipc.abc.binder.Person getPerson() throws android.os.RemoteException {
				// 创建输入对象,用于接收参数
                android.os.Parcel _data = android.os.Parcel.obtain();
				// 创建输出对象,用于返回值对象
                android.os.Parcel _reply = android.os.Parcel.obtain();
				// 被返回的值对象
                me.luzhuo.ipc.abc.binder.Person _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    mRemote.transact(Stub.TRANSACTION_getPerson, _data, _reply, 0); // 发起请求(setBinderUse())
                    _reply.readException();
                    if ((0 != _reply.readInt())) {
                        _result = me.luzhuo.ipc.abc.binder.Person.CREATOR.createFromParcel(_reply); // 从 _reply 取出返回结果
                    } else {
                        _result = null;
                    }
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result; // 返回数据
            }

            @Override
            public void setBinderUse(me.luzhuo.ipc.abc.binder.Person person) 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 ((person != null)) {
                        _data.writeInt(1);
                        person.writeToParcel(_data, 0); // 将参数写入 _data
                    } else {
                        _data.writeInt(0);
                    }
                    mRemote.transact(Stub.TRANSACTION_setBinderUse, _data, _reply, 0); // 发起 远程调用 请求, 同时当前线程挂起,直到服务端 onTransact 返回,当前线程继续执行, (所以不能在主线程发起请求)
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }
        }

		// 声明了int类型的id来标识方法
        static final int TRANSACTION_getPerson = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_setBinderUse = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    }

    public me.luzhuo.ipc.abc.binder.Person getPerson() throws android.os.RemoteException;

    public void setBinderUse(me.luzhuo.ipc.abc.binder.Person person) throws android.os.RemoteException;
}
Binder实现基本原理

Binder + Client + Server 完整案例代码

编写的AIDL文件,用于系统帮忙生成Binder文件

IBinderManager.aidl: IBinder最主要的AIDL文件,用于生成客户端与服务端通信的Binder代码

// 指定包名, 包名与java包名一致
package me.luzhuo.ipc.abc.binder;

// 在同一个包中,仍然需要导入 (就这一处)
// Parcelable 和 AIDL 数据类型的对象, 必须 import 进来
import me.luzhuo.ipc.abc.binder.Person;
import me.luzhuo.ipc.abc.binder.INewpersonListener;

 // AIDL接口中只支持声明方法,不支持声明静态变量
interface IBinderManager {
    // AIDL支持的数据类型: 基本数据类型, List(ArrayList), Map(HashMap), Parcelable, AIDL
    Person getPerson();
    // 除了基本数据类型,其他类型的参数须标上方向: in(输入参数) / out(输出参数) / inout(输入输出参数)
    void setBinderUse(in Person person);

    // 注册数据更新监听
    void registerUpdateListener(INewpersonListener listener);
    // 注销数据更新监听 (注意:对象是不能跨进程传递的, 服务端拿到的 INewpersonListener 对象是反序列化后的新对象, 但是binder对象将是同一个)
    void unregisterUpdateListener(INewpersonListener listener);
}

Person.aidl: 定义自定义的Parcelable对象

// 指定包名, 包名与java包名一致
package me.luzhuo.ipc.abc.binder;

// Model 类在AIDL中的声明
// AIDL文件中用到了自定义的Parcelable对象,必须新建一个与该类同名的AIDL文件, 如当前文件
parcelable Person;

INewpersonListener.aidl: 定义自定义接口, 用于服务端数据刷新时,可通过回调该接口通知客户端数据已更新

package me.luzhuo.ipc.abc.binder;

import me.luzhuo.ipc.abc.binder.Person;

interface INewpersonListener {
    // 服务端数据更新回调接口
    void onNewpersonUpdate(in Person person);
}

在进程A编写客户端

  1. 为了安全,添加的权限检验,并需要在清单文件中添加相关权限,即使是在一个应用中.
  2. 设置了死亡代理,一旦服务端死亡,将重启服务端并进行绑定.
  3. 由于客户端调用Binder里的方法后,当前线程会被挂起,直到服务端返回数据再次唤醒,所以要在辅助线程里调用.
  4. 服务端通过Binder里的方法通知客户端更新数据的回调接口中,不能执行耗时操作,因为服务端在等待客户端的结果,收到结果后唤醒;同样也不能更新UI,因为该回调方法执行于客户端的Binder线程池中.
  5. 服务端的回到方法通过使用Handler切换到UI线程进行UI更新操作.
public class BinderActivity extends AppCompatActivity {
    private static final String TAG = BinderActivity.class.getSimpleName();
    private static final int MESSAGE_PERSON_UPDATE = 0x0001;
    private IBinderManager binderManager = null;

    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case MESSAGE_PERSON_UPDATE:
                    Log.e(TAG, "message: " + msg.obj.toString());
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    };

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_binder);

        bindRemoteService(false);
    }

    /**
     * 绑定远程Service
     * @param isAfresh 是否是重新绑定
     */
    private void bindRemoteService(boolean isAfresh) {
        Log.e(TAG, "bindRemoteService");
        if (isAfresh) unbindService(mConnection);

        Intent intent = new Intent(this, BinderService.class);
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE); // 如果在清单文件定义了权限,则需要在清单文件添加权限,不然不能绑定
    }

    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            binderManager = IBinderManager.Stub.asInterface(iBinder);

            run("registerUpdateListener");

            // 设置死亡代理
            try {
                iBinder.linkToDeath(mDeathRecipient, 0);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            binderManager = null;
        }
    };

    private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient(){
        /**
         * 当 Binder 死亡的时候(可通过杀死服务进程模拟),系统回调该方法
         * 该方法运行Binder线程池
         */
        @Override
        public void binderDied() {
            if (binderManager == null) return;

            binderManager.asBinder().unlinkToDeath(mDeathRecipient, 0);
            binderManager = null;

            // 重新绑定远程Service
            bindRemoteService(true);
        }
    };

    public void setPerson(View view){
        run("setPerson");
    }

    public void getPerson(View view){
        run("getPerson");
    }

    private Random random = new Random();
    private void run(final String method){
        if (binderManager == null) return;

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {

                    if (method.equals("getPerson")) {
                        Person person = binderManager.getPerson();
                        Log.e(TAG, "getPerson: " + person.toString());
                    } else if (method.equals("setPerson")){
                        // 注意: 虽然该方法执行于服务端的Binder线程池中,但是当客户端发起请求时,客户端进程将被挂起,直到服务端返回数据唤醒, 所以要在辅助线程中执行
                        binderManager.setBinderUse(new Person("luzhuo", 21, "mimi" + random.nextInt()));
                    } else if (method.equals("registerUpdateListener")){
                        binderManager.registerUpdateListener(personUpdateListener);
                    } else if (method.equals("unregisterUpdateListener")){
                        binderManager.unregisterUpdateListener(personUpdateListener);
                    }

                }catch (RemoteException e){
                    e.printStackTrace();
                }
            }
        }).start();
    }

    INewpersonListener personUpdateListener = new INewpersonListener.Stub() {
        /**
         * 注意: 虽然该方法执行于客户端的Binder线程池中, 同样不能执行耗时操作, 原因同上
         */
        @Override
        public void onNewpersonUpdate(Person person) throws RemoteException {
            // 非UI线程, 不允许更新UI操作
            mHandler.obtainMessage(MESSAGE_PERSON_UPDATE, person).sendToTarget();
        }
    };


    @Override
    protected void onDestroy() {
        run("unregisterUpdateListener");
        unbindService(mConnection);

        mHandler.removeCallbacksAndMessages(null);
        mHandler = null;
        super.onDestroy();
    }
}

在进程B编写服务端

  1. 服务端可能会被多个客户端调用,所以要使用线程安全的类来存储变量,如:CopyOnWriteArrayList / AtomicBoolean

  2. public IBinder onBind(Intent intent) {} 里返回null的话会导致客户端绑定服务端失败

  3. private Binder mBinder = new IBinderManager.Stub(){
    	public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
    	}
    }
    

    里返回false会导致执行Binder里的方法失败(即使第2条绑定是成功的).

  4. 使用RemoteCallbackList类来存储回调接口,因为该类中使用了IBinder对象作为key,同一个客户端与客户端之间只有一个相同Ibinder对象.

    public class BinderService extends Service{
        private static final String TAG = BinderService.class.getSimpleName();
        // 如果有多个客户端连接该服务时,会并发而造成线程不安全
        // 线程安全(自动线程同步)的类: CopyOnWriteArrayList / ConcurrentHashMap
        private Person mPerson;
        private AtomicBoolean mServiceDestoryed = new AtomicBoolean(false);
        // RemoteCallbackList内部维护 ArrayMap<IBinder, Callback> 数据, 客户端传递的对象到服务端将被反序列化为新的对象,但是Binder对象始终是同一个
        private RemoteCallbackList<INewpersonListener> mListeners = new RemoteCallbackList<>();
    
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            // 权限过滤
            int check = checkCallingOrSelfPermission("me.luzhuo.ipc.permission.ACCESS_BINDER_SERVICE"); // 检查自己与其他调用者是否有该权限
            if (check == PackageManager.PERMISSION_DENIED) return null; // 如果没有该权限,则返回null
    
            return mBinder;
        }
    
        private Binder mBinder = new IBinderManager.Stub(){
            @Override
            public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
                // 权限过滤
                int check = checkCallingOrSelfPermission("me.luzhuo.ipc.permission.ACCESS_BINDER_SERVICE"); // 检查自己与其他调用者是否有该权限
                if (check == PackageManager.PERMISSION_DENIED) return false; // 如果没有该权限,则返回false(请求失败)
    
                // 验证包名: 使用Uid来获取包名,如果包名不是开始于"me.luzhuo则验证失败,验证不通过,则执行失败
                String[] packages = getPackageManager().getPackagesForUid(getCallingUid()); // 客户端的Uid:getCallingUid Pid: getCallingPid
            	if (packages != null && packages.length > 0)
                	if (!packages[0].startsWith("me.luzhuo")) return false;
    
                return super.onTransact(code, data, reply, flags);
            }
    
            @Override
            public Person getPerson() throws RemoteException {
                return mPerson;
            }
    
            @Override
            public void setBinderUse(Person person) throws RemoteException {
                mPerson = person;
    
                // 通知数据已更新
                final int listsSize = mListeners.beginBroadcast();
                for (int i = 0; i < listsSize; i++){
                    INewpersonListener listener = mListeners.getBroadcastItem(i);
    
                    if(listener == null) continue;
                    listener.onNewpersonUpdate(person);
                }
                mListeners.finishBroadcast();
            }
    
            @Override
            public void registerUpdateListener(INewpersonListener listener) throws RemoteException {
                mListeners.register(listener);
            }
    
            @Override
            public void unregisterUpdateListener(INewpersonListener listener) throws RemoteException {
                mListeners.unregister(listener);
            }
        };
    
        @Override
        public void onCreate() {
            super.onCreate();
            mPerson = new Person("null", 0, "null");
        }
    
        @Override
        public void onDestroy() {
            mServiceDestoryed.set(true);
            super.onDestroy();
        }
    }
    

清单文件中的权限

<uses-permission android:name="me.luzhuo.ipc.permission.ACCESS_BINDER_SERVICE" />

<!-- 添加服务端访问权限 -->
<permission android:name="me.luzhuo.ipc.permission.ACCESS_BINDER_SERVICE"
    android:protectionLevel="normal"/>
Binder池

上述Binder的使用中有个问题,就是如果我有多个不同的Binder来执行不同的类型的操作,那岂不是要创建多个服务端咯?-?,Binder池巧妙的解决了该问题: 不管你有多少个客户端,多少个不同类型的Binder,但始终保持一个服务端.

IBinderPool.aidl: 最主要的aidl文件,只有一个方法,就是根据提供的code返回指定的Binder

package me.luzhuo.ipc.cases.binderpool;

interface IBinderPool {
    /**
     * 根据 binderCode 返回对应的Binder对象
     */
    IBinder queryBinder(int binderCode);
}

IMath.aidl: 定义了一个数据计算的案例

package me.luzhuo.ipc.cases.binderpool;

interface IMath {
    // 加
    int add(int a, int b);
    // 减
    int subtract(int a, int b);
}

ISecurityCenter.aidl: 定义了一个加解密的案例

package me.luzhuo.ipc.cases.binderpool;

interface ISecurityCenter {
    // 加密
    String encrypt(String content);
    // 解密
    String decrypt(String password);
}

然后实现定义的功能Binder类

// MathImpl.java
public class MathImpl extends IMath.Stub{
    @Override
    public int add(int a, int b) throws RemoteException {
        return a + b;
    }

    @Override
    public int subtract(int a, int b) throws RemoteException {
        return a - b;
    }
}

// SecurityCenterImpl.java
public class SecurityCenterImpl extends ISecurityCenter.Stub{

    @Override
    public String encrypt(String content) throws RemoteException {
        return content + "已加密";
    }

    @Override
    public String decrypt(String password) throws RemoteException {
        return password + "已解密";
    }
}

BinderPool.java: 重点来啦, 这是Binder池类, 使用了单例设计模式,创建对象时绑定服务;queryBinder会根据用于传入的int标志返回不同功能的Binder类.

public class BinderPool {
    public static final int BINDER_SECURITY_CENTER = 0x001, BINDER_COMPUTE = 0x002;

    private Context mContext;
    private IBinderPool mBinderPool;
    private static BinderPool instance;

    private BinderPool(Context context){
        mContext = context.getApplicationContext();
        connectBinderPoolService();
    }

    public static BinderPool getInstance(Context context){
        if (instance == null){
            synchronized (BinderPool.class){
                if (instance == null){
                    instance = new BinderPool(context);
                }
            }
        }
        return instance;
    }

    public IBinder queryBinder(int binderCode){
        IBinder binder = null;
        try{
            if (mBinderPool != null){
                binder = mBinderPool.queryBinder(binderCode);
            }
        }catch (RemoteException e){
            e.printStackTrace();
        }
        return binder;
    }

    private synchronized void connectBinderPoolService() {
        Intent intent = new Intent(mContext, BinderPoolService.class);
        mContext.bindService(intent, binderPoolConnection, Context.BIND_AUTO_CREATE);
    }

    private ServiceConnection binderPoolConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            mBinderPool = IBinderPool.Stub.asInterface(iBinder);
            try{
                mBinderPool.asBinder().linkToDeath(mDeathRecipient, 0);
            }catch (RemoteException e){
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {

        }
    };

    private IBinder.DeathRecipient mDeathRecipient = new Binder.DeathRecipient(){
        @Override
        public void binderDied() {
            mBinderPool.asBinder().unlinkToDeath(mDeathRecipient, 0);
            mBinderPool = null;
            connectBinderPoolService();
        }
    };

    /**
     * 通过工厂方法设计模式返回对应的Binder对象
     */
    public static class BinderPoolImpl extends IBinderPool.Stub{
        @Override
        public IBinder queryBinder(int binderCode) throws RemoteException {
            IBinder binder = null;
            switch (binderCode){
                case BINDER_SECURITY_CENTER:
                    binder = new SecurityCenterImpl();
                    break;
                case BINDER_COMPUTE:
                    binder = new MathImpl();
                    break;
            }
            return binder;
        }
    }
}

在A进程的服务端: 与之前使用是相同的,就是给服务绑定一个Binder

public class BinderPoolService extends Service{
    private Binder mBinder = new BinderPool.BinderPoolImpl();

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        // 权限过滤
        int check = checkCallingOrSelfPermission("me.luzhuo.ipc.permission.ACCESS_BINDER_SERVICE");
        if (check == PackageManager.PERMISSION_DENIED) return null;

        return mBinder;
    }
}

在B进程的客户端: 首先创建Binder池,然后从池里取出(实际是创建)不同功能的Binder,然后调用其方法.这里的方法调用仍然需要注意如果执行的是耗时任务需要放在辅助线程里执行.

public class BinderPoolActivity extends AppCompatActivity {
    private static final String TAG = BinderPoolActivity.class.getSimpleName();
    private BinderPool binderPool;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_binderpool);

        binderPool = BinderPool.getInstance(this);
    }

    public void onlick1(View view){
        IBinder securityBinder = binderPool.queryBinder(BinderPool.BINDER_SECURITY_CENTER);
        ISecurityCenter securityCenter = SecurityCenterImpl.asInterface(securityBinder);
        String msg = "asdfasf";
        try{
			// 调用方法要放到辅助线程里执行,因为调用发后,当前线程会被挂起,直到返回结果唤醒
            String password = securityCenter.encrypt(msg);
            Log.e(TAG, "password: " + password);
        }catch (RemoteException e){
            e.printStackTrace();
        }
    }

    public void onlick2(View view){
        IBinder computeBinder = binderPool.queryBinder(BinderPool.BINDER_COMPUTE);
        IMath mCompute = MathImpl.asInterface(computeBinder);
        try{
            int num = mCompute.add(1, 2);
            Log.e(TAG, "num: " + num);
        }catch (RemoteException e){
            e.printStackTrace();
        }
    }
}
ContentProvider

ContentProvider(内容提供者)是基于Binder实现的, 主要用于共享数据, 统一了数据的访问方式.

DBOpenHelper.java: 数据库帮助类

public class DBOpenHelper extends SQLiteOpenHelper {
    private static DBOpenHelper openHelper;

    public static final String DB_NAME = "person.db";
    public static final String PERSON_TABLE_NAME = "person";
    public static final int VERSION_0 = 0; // 起始版本
    public static final int VERSION_1 = 1;
    public static final int DB_VERSION = 2; // 当前版本

    // Person
    public static final String TABLE_ID = "_id";
    public static final String TABLE_NAME = "name";

    private DBOpenHelper(Context context) {
        super(context, DB_NAME, null, DB_VERSION);
    }

    public static DBOpenHelper getInstance(Context context){
        // 单例模式获取数据库帮助类对象
        if(openHelper == null){
            synchronized (DBOpenHelper.class){
                if(openHelper == null){
                    openHelper = new DBOpenHelper(context);
                }
            }
        }
        return openHelper;
    }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        sqLiteDatabase.execSQL("CREATE TABLE IF NOT EXISTS "+ PERSON_TABLE_NAME + "(" + TABLE_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + TABLE_NAME + " VARCHAR(100))");
        onUpgrade(sqLiteDatabase, VERSION_0, DB_VERSION);
    }

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
        switch (oldVersion){
            case VERSION_0:
                // 修改数据库结构的操作
            case VERSION_1:
            case DB_VERSION:
                break;
        }
    }
}

PersonProvider.java: 内容提供者

public class PersonProvider extends ContentProvider {
    public static final String AUTHORITY = "me.luzhuo.person_provider"; // 唯一识别码
    private static final UriMatcher mUriMatcher;
    private SQLiteDatabase db; //person数据库帮助对象

    public static final int PERSON_URI_CODE = 0; // 匹配码

    // 指定URI 与 相关URICode
    public static final Uri PERSON_CONTENT_URI = Uri.parse("Content://" + AUTHORITY + "/person");



    static {
        mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        // Content://me.luzhuo.person_provider/person
        mUriMatcher.addURI(AUTHORITY, "person", PERSON_URI_CODE); // 添加URI
        // mUriMatcher.match(uri); // 匹配完整URI
    }

    @Override
    public boolean onCreate() {
        // 运行于主线程
        db = DBOpenHelper.getInstance(getContext()).getWritableDatabase();
        return true;
    }

    public String getTableName(Uri uri){
        String tableName = null;
        switch (mUriMatcher.match(uri)){
            case PERSON_URI_CODE:
                tableName = DBOpenHelper.PERSON_TABLE_NAME;
                break;
        }
        return tableName;
    }

    @Nullable
    @Override
    public Cursor query(Uri uri, String[] columns, String selection, String[] selectionArgs, String orderBy) {
        // 运行于Binder线程池
        String table = getTableName(uri);
        if (table == null) throw new IllegalArgumentException("Uri错误,没有找到该表: " + uri);

        return db.query(table, columns, selection, selectionArgs, null, null, orderBy, null);
    }

    @Nullable
    @Override
    public String getType(Uri uri) {
        // 运行于Binder线程池
        return null;
    }

    @Nullable
    @Override
    public Uri insert(Uri uri, ContentValues contentValues) {
        // 运行于Binder线程池
        String table = getTableName(uri);
        if (table == null) throw new IllegalArgumentException("Uri错误,没有找到该表: " + uri);

        long id = db.insert(table, null, contentValues);
        getContext().getContentResolver().notifyChange(uri, null); // 通知内容观察者数据更新
        return ContentUris.withAppendedId(uri, id); // 追加id
        // long id = ContentUris.parseId(uri); // 解析id
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        // 运行于Binder线程池
        String table = getTableName(uri);
        if (table == null) throw new IllegalArgumentException("Uri错误,没有找到该表: " + uri);

        int count = db.delete(table, selection, selectionArgs);
        if(count > 0) getContext().getContentResolver().notifyChange(uri, null);

        return count;
    }

    @Override
    public int update(Uri uri, ContentValues contentValues, String selection, String[] selectionArgs) {
        // 运行于Binder线程池
        String table = getTableName(uri);
        if (table == null) throw new IllegalArgumentException("Uri错误,没有找到该表: " + uri);

        int row = db.update(table, contentValues, selection, selectionArgs);
        if (row > 0) getContext().getContentResolver().notifyChange(uri, null);

        return row;
    }
}

ContentProviderActivity.java: 内容提供者的使用

public class ContentProviderActivity extends AppCompatActivity{
    private static final String TAG = ContentProviderActivity.class.getSimpleName();
    Uri uri = Uri.parse("content://me.luzhuo.person_provider/person");

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_provider);

        // 注册一个内容观察者观察数据库的改变
        getContentResolver().registerContentObserver(uri, true, new MyContentObserver(new Handler()));
    }

    public void add(View view){
        ContentValues values = new ContentValues();
        values.put("name", "luzhuo" + new Random().nextInt());

        Uri uriId = getContentResolver().insert(uri, values);
        Log.e(TAG, "添加到: " + ContentUris.parseId(uriId));
    }

    public void delete(View view){
        int count = getContentResolver().delete(uri, "_id = ?", new String[]{"21"});
        Log.e(TAG, "删除行:"+count);
    }

    public void update(View view){
        ContentValues values = new ContentValues();
        values.put("name", "test");

        int count = getContentResolver().update(uri, values, "_id = ?", new String[]{"2"});
        Log.e(TAG, "更新行: " + count);
    }

    public void query(View view){
        Cursor cursor = getContentResolver().query(uri, new String[]{"_id", "name"}, null, null, null);

        if(cursor == null || cursor.getCount() <= 0) return;

        while (cursor.moveToNext()){
            Person person = new Person();
            int id = cursor.getInt(0);
            person.name = cursor.getString(1);
            Log.e(TAG, person.toString());
        }
        cursor.close();
    }


    /**
     * 内容观察者
     */
    public static class MyContentObserver extends ContentObserver {
        private static final String TAG = MyContentObserver.class.getSimpleName();

        public MyContentObserver(Handler handler) {
            super(handler);
        }
        // 当被监听的内容发生改变时回调
        @Override
        public void onChange(boolean selfChange) {
            Log.e(TAG, "数据库数据发生改变了.");
        }
    }
}

清单配置

<uses-permission android:name="me.luzhuo.permission.READ_PROVIDER" />
<uses-permission android:name="me.luzhuo.permission.WRITE_PROVIDER" />

<application>
    <!-- 内容提供者 -->
    <provider
        android:authorities="me.luzhuo.person_provider"
        android:name=".cases.contentprovider.PersonProvider"
        android:readPermission="me.luzhuo.permission.READ_PROVIDER"
        android:writePermission="me.luzhuo.permission.WRITE_PROVIDER"
        android:process=":provider" />
    <activity android:name=".cases.contentprovider.ContentProviderActivity" />
</application>

Socket

Socket原本是用来网络传输数据用的,当来也是可以用来本地不同的进程之间通信
本地通信与网络通信的代码是相同的

SocketActivity.java: 客户端

public class SocketActivity extends AppCompatActivity {
    private static final String TAG = SocketActivity.class.getSimpleName();
    private TextView messageView, sendmessage;
    private static final int MESSAGE_CONNECTED = 0X001, MESSAGE_RECEIVE = 0x002;

    private Socket socket = null;
    private PrintWriter writer;
    private BufferedReader reader;

    Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case MESSAGE_CONNECTED:
                    sendmessage.setEnabled(true);
                    break;
                case MESSAGE_RECEIVE:
                    messageView.append(msg.obj + "\r\n");
                    break;
                default:
                    super.handleMessage(msg);
                    break;
            }
        }
    };

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_socket);

        messageView = (TextView) findViewById(R.id.message);
        sendmessage = (TextView) findViewById(R.id.sendmessage);

        Intent intent = new Intent(this, SocketService.class);
        startService(intent);

        runThread("connectTCPServer");
    }

    /**
     * 向服务端发送消息
     * @param view
     */
    public void send(View view){
        if (writer == null) throw new NullPointerException();

        String message = "我是消息: " + new Random().nextInt();
        runThread("sendMessage", message);
        messageView.append("客户端发送: " + message + "\r\n");
    }

    /**
     * 运行于辅助线程的命令
     * @param command
     */
    public void runThread(final String command, final Object... obj){
        new Thread(){
            @Override
            public void run() {
                if (command.equals("connectTCPServer")){
                    connectTCPServer();
                } else if (command.equals("receiveServerMessage")){
                    receiveServerMessage();
                } else if (command.equals("sendMessage")){
                    sendMessage((String)obj[0]);
                }
            }
        }.start();
    }

    /**
     * 发送消息
     */
    private void sendMessage(String message) {
        if (writer == null) throw new NullPointerException();

        writer.println(message);
    }

    /**
     * 接收服务端消息
     */
    private void receiveServerMessage() {
        if (reader == null) throw new NullPointerException();

        try {
            // 接收服务端的消息
            while (!this.isFinishing()){
                String msg = reader.readLine();
                Log.e(TAG, "客户端收到服务端的消息: " +  msg);
                if(msg !=null){
                    handler.obtainMessage(MESSAGE_RECEIVE, msg).sendToTarget();
                }
            }
            reader.close();
        }catch (IOException e){
            e.printStackTrace();
        }
    }

    /**
     * 连接服务端
     */
    private void connectTCPServer() {
        while(socket == null){
            try{
                socket = new Socket("localhost", 10086);
                writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
                reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));

                handler.sendEmptyMessage(MESSAGE_CONNECTED);

                Log.e(TAG, "与服务端连接成功");
            }catch (IOException e){
                SystemClock.sleep(1000); // 连接失败,每1秒进行重试
                e.printStackTrace();
            }
        }

        runThread("receiveServerMessage");
    }

    @Override
    protected void onDestroy() {
        if (socket != null){
            try{
                writer.close();
                socket.shutdownOutput();
                reader.close();
                socket.shutdownInput();
                socket.close();
            }catch (IOException e){
                e.printStackTrace();
            }
        }
        super.onDestroy();
    }
}

SocketService.java: 服务端

public class SocketService extends Service {
    private static final String TAG = SocketService.class.getSimpleName();
    private boolean serviceDestoryed = false;
    private ServerSocket serverSocket;

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        runThread("createSocket");

        super.onCreate();
    }

    /**
     * 运行于辅助线程的命令
     * @param command
     */
    public void runThread(final String command){
        new Thread(){
            @Override
            public void run() {
                if (command.equals("createSocket")){
                    createSocket();
                }
            }
        }.start();
    }

    /**
     * 接收客户端消息
     */
    private void receiveClientMessage() {
        if(serverSocket == null) throw new NullPointerException();

        while (!serviceDestoryed){
            try {
                // 处理客户请求
                final Socket client = serverSocket.accept();
                new Thread(){
                    @Override
                    public void run() {
                        try {
                            BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
                            PrintWriter writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(client.getOutputStream())), true);
                            writer.println("服务端已连接");
                            while (!serviceDestoryed){
                                String str = reader.readLine();
                                Log.e(TAG, "接收到客户端消息: " + str);

                                if(str == null) break; // 已断开连接

                                String msg = "服务端已收到您的消息: " + str;
                                writer.println(msg);
                            }
                            writer.close();
                            reader.close();
                            client.close();
                        }catch (IOException e){
                            e.printStackTrace();
                        }
                    }
                }.start();
            }catch (IOException e){
                e.printStackTrace();
            }
        }
    }

    /**
     * 创建Socket并监听本地端口
     */
    private void createSocket() {
        try {
            serverSocket = new ServerSocket(10086);

            receiveClientMessage();
        }catch (IOException e){
            e.printStackTrace();
        }
    }

    @Override
    public void onDestroy() {
        serviceDestoryed = true;
        super.onDestroy();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值