Binder的使用

Binder:从应用层面上来看,binder是进程间通信的媒介,从framework层看,它是各种Manager(比如WindowManager,ActivityManager)等和相应的ManagerService(WindowManagerService,ActivityManagerService)进行通信的桥梁。从硬件层面来看,它也像是个binder 驱动。它实现了IBinder接口。它是android特有的一种跨进程的通信方式,它的的作用是Android 的进程间进行通信。

下面看看如何使用Binder进行进程间的通信。
1.首先在app目录的src/main目录下,新建一个aidl的文件夹,然后在adil文件夹下,右键,package,包名就填写manifest文件中 的包名。

2.在新建的包的目录下,创建IPalyInterface.aidl文件和IDownLoadInterface.aidl文件以及IBindPool.aidl文件,下面分别是三个文件中的内容:

// IPlayInterface.aidl
package test.cn.example.com.androidskill;

// Declare any non-default types here with import statements

interface IPlayInterface {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
//    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
//            double aDouble, String aString);

    void palyMusic(String musicName);
}

IDownLoadInterface.adil文件

// IDownLoadInterface.aidl
package test.cn.example.com.androidskill;

// Declare any non-default types here with import statements

interface IDownLoadInterface {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
//    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
//            double aDouble, String aString);

    void downLoad(String url);
}

IBindPoolInterface.aidl文件

// IBindPoolInterface.aidl
package test.cn.example.com.androidskill;

// Declare any non-default types here with import statements

interface IBindPoolInterface {

     IBinder queryBinder(int requestCode);
}

创建完这三个aidl文件后,点击Build选项下的Make Project 按钮,项目完成构建后,在
app/build/generate/sorce/adil/ceshi/debug/包名/ 这个目录下,就会看到生成的相应的IPlayInterface,IDownLoadInterface , IBindPoolInterface三个java文件。完成这个步骤后,其实就已经生成了Binder了。如果不是很明白,可以参考这篇博客:
《Android Studio中如何建立AIDL文件&生成及找到相应的.java文件》

3.新建一个类名为 BindPoolService的java文件,记得在manifest文件中注册,并设置process属性,使其运行在一个单独的进程中。下面是BindPoolService.java的代码:

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.Process;

import androidx.annotation.Nullable;

import test.cn.example.com.androidskill.art.chapter_two.BindPool;
import test.cn.example.com.util.LogUtil;
public class BindPoolService extends Service {

    private Binder mBinder;

    @Override
    public void onCreate() {
        super.onCreate();
        LogUtil.e("onCreate "+"Process.myPid()=   "+ Process.myPid());
        mBinder = new BindPool.IBindPoolImpl();
    }

    @Nullable
    @android.support.annotation.Nullable
    @Override
    public IBinder onBind(Intent intent) {
        LogUtil.e("mBinder = "+mBinder);
        return mBinder;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        LogUtil.e("onDestroy ");
    }
}

在onBind方法中返回的mBinder是BindPool类中的静态类,下面看看BindPool类的代码:

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;

import java.util.concurrent.CountDownLatch;

import test.cn.example.com.androidskill.IBindPoolInterface;
import test.cn.example.com.androidskill.service.BindPoolService;
import test.cn.example.com.util.LogUtil;

public class BindPool {
    private static final int REQUEST_CODE_PLAYMUSIC = 1;
    private static final int REQUEST_CODE_DOWNLOAD = 2;
    private final Context mContext;
    private CountDownLatch countDownLatch;
    private static BindPool instance;
    private static IBindPoolInterface iBindPoolInterface;

    private BindPool(Context context){
        mContext = context.getApplicationContext();
        connectService(mContext);
    }

    private synchronized void connectService(Context context) {
        countDownLatch = new CountDownLatch(1);
        Intent intent = new Intent(context, BindPoolService.class);
        context.bindService(intent,mServiceConnection,Context.BIND_AUTO_CREATE);

        try {
            //这里要等待,连接上Servcie后,才能继续执行queryBinder方法,否则,queryBinder方法中的
            // iBindPoolInterface 就是 null
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

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

    private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            LogUtil.e("servcie connected ");
            iBindPoolInterface = IBindPoolInterface.Stub.asInterface(service);
            try {
                iBindPoolInterface.asBinder().linkToDeath(mBinderPoolDeathRecipient,0);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
            //和服务端连接成功后,就解除阻塞的线程,这样queryBinder方法才能执行
            countDownLatch.countDown();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            LogUtil.e("service disconnect ");
        }
    };

    public void disconnectServcie(){
        if(null != mServiceConnection && null != mContext){
            mContext.unbindService(mServiceConnection);
        }
    }

    private IBinder.DeathRecipient mBinderPoolDeathRecipient = new IBinder.DeathRecipient() {
        @Override
        public void binderDied() {
            LogUtil.e("bind die");
            iBindPoolInterface.asBinder().unlinkToDeath(mBinderPoolDeathRecipient,0);
            connectService(mContext);
        }
    };

    public IBinder queryBinder(int requestCode) throws RemoteException{
        LogUtil.e("iBindPoolInterface =  "+iBindPoolInterface);
        if(null != iBindPoolInterface){
            return iBindPoolInterface.queryBinder(requestCode);
        }
        return null;
    }


    public static  class IBindPoolImpl extends  IBindPoolInterface.Stub{

        @Override
        public IBinder queryBinder(int requestCode) throws RemoteException {
            IBinder iBinder = null;
            switch (requestCode){
                case REQUEST_CODE_PLAYMUSIC:
                    iBinder = new IPlayImpl();
                    break;
                case REQUEST_CODE_DOWNLOAD:
                    iBinder = new IDownLoadImpl();
                    break;
            }
            return iBinder;
        }
    }

}

下面是IPlayImpl类和IDownLoadImpl的代码:

IPlayImpl.java

import android.os.Process;
import android.os.RemoteException;

import test.cn.example.com.androidskill.IPlayInterface;
import test.cn.example.com.util.LogUtil;

public class IPlayImpl extends IPlayInterface.Stub {
    @Override
    public void palyMusic(String musicName) throws RemoteException {
        LogUtil.e("播放的歌曲是   "+musicName+"       Process.myPid()=   "+ Process.myPid());
    }
}

IDownLoadImpl.java

import android.os.Process;
import android.os.RemoteException;

import test.cn.example.com.androidskill.IDownLoadInterface;
import test.cn.example.com.util.LogUtil;

public class IDownLoadImpl extends IDownLoadInterface.Stub {
    @Override
    public void downLoad(String url) throws RemoteException {
        LogUtil.e("下载的url地址是   "+url+"       Process.myPid()=   "+ Process.myPid());
    }
}

完成了上面的步骤后,就可以在Activity中使用了:

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

          try {
             //   1  
              IBinder iPlayBinder = BindPool.getInstance(ChapterTwoActivity.this).queryBinder(1); 
              LogUtil.e("iPlayBinder =  "+iPlayBinder);
              if(null != iPlayBinder){
                  IPlayInterface iPlayInterface = IPlayInterface.Stub.asInterface(iPlayBinder);
                  iPlayInterface.palyMusic("说好不哭");
              }

              IBinder iDownLoadBinder = BindPool.getInstance(ChapterTwoActivity.this).queryBinder(2);
              LogUtil.e("iDownLoadBinder =  "+iDownLoadBinder);
              if(null != iDownLoadBinder){
                  IDownLoadInterface iDownLoadInterface = IDownLoadInterface.Stub.asInterface(iDownLoadBinder);
                  iDownLoadInterface.downLoad("www.kugo.com");
              }

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

      }
}).start();

总结:上面整个过程是通过一个binder连接池来和一个Service建立连接,连接成功后,会返回一个远程服务端的binder代理对象,这个对象就是BindPool类中的iBindPoolInterface,这样就可以通过iBinderPoolInterface这个远程服务的代理对象,通过queryIBinder方法中传入的不同的requestCode,向远程服务发起queryBinder,这样远程服务端的mBinder对象就会响应queryBinder(int requestCode)方法,由于服务端返回的Binder就是IBindPoolImpl这个对象,所以BindPool类中的IBindPoolImpl的queryBinder(int requestCode)方法就得到执行,再通过请求的requestCode返回一个Binder对象给客户端进程,假设这里返回的是IPlayImpl这个Binder对象,这样客户端进程拿到这个IPlayImpl这个Binder对象的代理后,在通过这个代理来发起请求,后面再次进行进程间通信,最终在服务端会执行IPlayImpl这个Binder中的具体方法,如果这个方法有返回值,就将结果返回给
客户端进程。由于在客户端调用通过BindPool初始化时,也进行了和远程服务进行连接,所以,如果服务端还未和客户端建立连接,那么立刻调用BindPool.getInstance(ChapterTwoActivity.this).queryBinder(1)方法时,可能此时iBindPoolInterface这个对象还是null,所以,为了避免这种情况的出现, 我们在bindService后,通过CountDownLatch这个线程对象的await()方法,将当前线程阻塞,知道和服务端建立了连接后,这样iBindPoolInterface才会赋值,这时,在将取消当前线程的阻塞状态,这样后续的操作才能正常的进行。

上面只是演示了如何使用aidl,生成Binder,进行进程间的通信。下面,从应用层,简要分析下,binder的具体执行过程。
在上面的代码注释1 处,这行代码 IBinder iPlayBinder = BindPool.getInstance(ChapterTwoActivity.this).queryBinder(1);
这样代码会执行BindPool类中的queryBinder方法,

    public IBinder queryBinder(int requestCode) throws RemoteException{
        LogUtil.e("iBindPoolInterface =  "+iBindPoolInterface);
        if(null != iBindPoolInterface){
            return iBindPoolInterface.queryBinder(requestCode);
        }
        return null;
    }

这个方法里面
iBindPoolInterface.queryBinder(requestCode)就是具体的客户端级进程开始向服务端进程发起的请求的开始处。
由于iBindPoolInterface是服务端进程的Binder对象的一个代理对象,下面看看这个代理对象是什么:

public interface IBindPoolInterface extends android.os.IInterface {
    /**
     * Local-side IPC implementation stub class.
     */
    public static abstract class Stub extends android.os.Binder implements test.cn.example.com.androidskill.IBindPoolInterface {
        private static final java.lang.String DESCRIPTOR = "test.cn.example.com.androidskill.IBindPoolInterface";

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

        /**
         * Cast an IBinder object into an test.cn.example.com.androidskill.IBindPoolInterface interface,
         * generating a proxy if needed.
         */
        public static test.cn.example.com.androidskill.IBindPoolInterface asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof test.cn.example.com.androidskill.IBindPoolInterface))) {
                return ((test.cn.example.com.androidskill.IBindPoolInterface) iin);
            }
            return new test.cn.example.com.androidskill.IBindPoolInterface.Stub.Proxy(obj);
        }

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

        @Override
        public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
            java.lang.String descriptor = DESCRIPTOR;
            switch (code) {
                case INTERFACE_TRANSACTION: {
                    reply.writeString(descriptor);
                    return true;
                }
                case TRANSACTION_queryBinder: {
                    data.enforceInterface(descriptor);
                    int _arg0;
                    _arg0 = data.readInt();
                    android.os.IBinder _result = this.queryBinder(_arg0);
                    reply.writeNoException();
                    reply.writeStrongBinder(_result);
                    return true;
                }
                default: {
                    return super.onTransact(code, data, reply, flags);
                }
            }
        }

        private static class Proxy implements test.cn.example.com.androidskill.IBindPoolInterface {
            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 android.os.IBinder queryBinder(int requestCode) throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                android.os.IBinder _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeInt(requestCode);
                    mRemote.transact(Stub.TRANSACTION_queryBinder, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readStrongBinder();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
        }

        static final int TRANSACTION_queryBinder = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    }

    public android.os.IBinder queryBinder(int requestCode) throws android.os.RemoteException;
}

这个代理对象其实就是IBindPoolInterface,Stub.Proxy这个类的实例。这个IBindPoolInterface,Stub.Proxy对test.cn.example.com.androidskill.IBindPoolInterface接口中的queryBinder进行了具体的实现,所以,当iBindPoolInterface调用queryBinder方法时,具体就执行到了IBindPoolInterface,Stub.Proxy类中的queryBinder方法,这样 mRemote.transact(Stub.TRANSACTION_queryBinder, _data, _reply, 0);方法就执行了,这里的mRemotej就是一个IBindPoolInterface,Stub,IBindPoolInterface,Stub其实是继承Binder的,所以mRemote对象也就是一个Binder对象,这样就开始通过Binder发起进程间通信了。这个过程可以看下面这个图:图1
在这里插入图片描述
上面介绍的过程,就是上面这幅图中Clinet------->远程请求------>Binder----------->Transact这个过程。
具体Transact-------------->Servcie--------------->OnTransact过程,可以参考下面这个图:图2
在这里插入图片描述
客户端通过的Binder代理对象发起请求,到mRemote.transact(Stub.TRANSACTION_queryBinder, _data, _reply, 0);后,
服务端的Binder的onTransact方法就执行了,下面看看服务端返回的Binder,通过上面的BindPoolService代码,可以知道,服务端返回的Binder其实就是BindPool.IBindPoolImpl这个对象,这个IBindPoolImpl类是继承IBindPoolInterface.Stub,所以,服务端的onTransact方法的执行,就是调用了IBindPollImpl这个Binder的onTransact方法,也就是其父类IBindPoolInterface.Stub类中的onTransact方法:

        @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_queryBinder: {
                    data.enforceInterface(descriptor);
                    int _arg0;
                    _arg0 = data.readInt();
                    // 关键代码
                    android.os.IBinder _result = this.queryBinder(_arg0);
                    reply.writeNoException();
                    reply.writeStrongBinder(_result);
                    return true;
                }
                default: {
                    return super.onTransact(code, data, reply, flags);
                }
            }
        }

这个方法内部,最后会调用 this.queryBinder(_arg0),这个方法其实最终会调用到BindPool.IBindPoolImpl类的queryBinder方法

public static  class IBindPoolImpl extends  IBindPoolInterface.Stub{

        @Override
        public IBinder queryBinder(int requestCode) throws RemoteException {
            IBinder iBinder = null;
            switch (requestCode){
                case REQUEST_CODE_PLAYMUSIC:
                    iBinder = new IPlayImpl();
                    break;
                case REQUEST_CODE_DOWNLOAD:
                    iBinder = new IDownLoadImpl();
                    break;
            }
            return iBinder;
        }
    }

这个方法最终会根据请求的requestCode返回相应的Binder对象给客户端。这就是整个Binder的进程间通信的过程。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值