Android:让我们来写一写Binder

Posted bdmh

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android:让我们来写一写Binder相关的知识,希望对你有一定的参考价值。

Binder作为android中跨进程通信的一部分,在源码中是起了极其重要的作用。比如ActivityManagerService,就是通过Binder来控制Activity的操作。至于Binder的通信,很多文章都是通过创建AIDL工程,由工具自动生成代码,就会看到诸如Stub、Proxy等内部类,看的是一头雾水。所以要想明明白白的使用Binder,自己手写一遍,对理解是非常有效的。

以下以在两个进程间通信为例来写一个Binder。

客户端

首先定义一个接口,包括Binder标识,发送Transact消息,接口定义等。

public interface IMyManager extends IInterface 
    String DESCRIPTOR = "my.study.IMyManager";
    int Transact_Hello = IBinder.FIRST_CALL_TRANSACTION + 0;
    void hello() throws RemoteException;

再定义一个和Server端的的协议类。实现IMyManager接口。

public class MyProxy implements IMyManager 
    private IBinder binder;
    public MyProxy(IBinder token)
        binder = token;
    
    @Override
    public IBinder asBinder() 
        return binder;
    
    public java.lang.String getInterfaceDescriptor()
    
        return DESCRIPTOR;
    

    @Override
    public void hello() throws RemoteException 
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeString("中国");
        data.writeInt(100);
        binder.transact(Transact_Hello,data,reply,0);
        Log.e("服务端返回",reply.readString());
        Log.e("服务端返回",reply.readInt()+"");
    

上面代码中的hello方法,将负责和Server端进行交互,将transact消息发送给Server端,data可以写入信息,由Server端接收,reply是由Server端填充数据,返回给客户端读取。

接下来定义一个Stub,名字可以随意。因为不考虑在客户端创建,所以在客户端一方,我们只保留一个方法,用来转化IBinder接口,如果确保服务不是本进程的话,只需要最后一句即可。

public abstract class MyManager extends Binder implements IMyManager 
    public static IMyManager asInterface(IBinder obj)
        if (obj == null)
            return null;
//取出指定描述的接口,判断是不是本进程的
        IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
        if (iin != null && iin instanceof IMyManager)
            return (IMyManager)iin;
        
//如果不是,new一个协议对象
        return new MyProxy(obj);
    

在客户端如何使用呢?比如在Activity中,创建时,可以绑定Server端的服务。

private IMyManager myService;
private ServiceConnection serviceConnection;

serviceConnection = new ServiceConnection() 
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) 
        myService = MyManager.asInterface(service);
    

    @Override
    public void onServiceDisconnected(ComponentName name) 
        myService = null;
    
;
//com.mh.binderserver为服务端的包名,后面提到
Intent intent = new Intent("com.mh.binderserver.MyService");
//指明服务端包名
intent.setPackage("com.mh.binderserver");
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);

在Activity的按钮点击事件中写

try 
    myService.hello();
 catch (RemoteException e) 
    e.printStackTrace();

这样,客户端的任务就完成了,下面我们看服务端。

服务端

首先,和客户端一样,先定义一个接口:

public interface IMyManager extends IInterface 
    String DESCRIPTOR = "my.server.IMyManager";
    int Transact_Hello = IBinder.FIRST_CALL_TRANSACTION + 0;

和客户端不一样,这里就不需要Proxy类了。然后定义MyManager。

public class MyManager extends Binder implements IMyManager 
    public MyManager()
        this.attachInterface(this,DESCRIPTOR);
    
    @Override
    public IBinder asBinder() 
        return this;
    

    @Override
    protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException 
        switch (code)
            case Transact_Hello:
                Log.e("客户端传来",data.readString());
                Log.e("客户端传来",data.readInt()+"");
                reply.writeString("北京");
                reply.writeInt(200);
                return true;
        
        return super.onTransact(code, data, reply, flags);
    

因为在服务端要创建Binder,所以这里构造方法中,要附加指定标识的接口。类似于注册一样。onTransact就是Binder中最重要的用来接收各方信息的入口。data和reply对应客户端Proxy中hello方法中发送的data和reply。

因为客户端要bind一个Service,所以服务端需要有一个Service对象。

public class MyService extends Service 
//创建上面的MyManager对象
    private final MyManager binder = new MyManager();

    @Override
    public void onCreate() 
        super.onCreate();
    

    @Override
    public IBinder onBind(Intent intent) 
        return binder;
    

然后在AndroidManifest中声明这个Service。注意action的name,就是客户端绑定Service时的那个intent中的action名字,要一致。

<service android:name=".MyService">
    <intent-filter>
        <action android:name="com.mh.binderserver.MyService" />
    </intent-filter>
</service>

服务端启动Service。

startService(new Intent(this,MyService.class));

先启动Server端,然后在打开客户端,点击客户端页面上的按钮,日志中就会显示:

com.mh.binderserver E/客户端传来: 中国
com.mh.binderserver E/客户端传来: 100
my.study E/服务端返回: 北京
my.study E/服务端返回: 200

至此一个Binder操作完成。这样,当你再次去看Activity启动过程时,对ActivityManagerService的理解可能就明了多了。

以上是关于Android:让我们来写一写Binder的主要内容,如果未能解决你的问题,请参考以下文章

简单写一写keepalived

Java泛型的应用

Android 根据EditText搜索框ListView动态显示数据

寒假这十天

把Unity作为Android的子视图

noip多校21