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的理解可能就明了多了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,下面是一个简单的 Android Binder Demo。 首先,我们定义一个 AIDL 接口文件 `IDemoService.aidl`,它包含一个方法 `int add(int a, int b)`,用于计算两个整数的和。 ```aidl // IDemoService.aidl interface IDemoService { int add(int a, int b); } ``` 然后,我们实现这个接口,创建一个名为 `DemoService` 的服务类,它继承自 `IDemoService.Stub`,实现 `add()` 方法。 ```java // DemoService.java public class DemoService extends IDemoService.Stub { @Override public int add(int a, int b) throws RemoteException { return a + b; } } ``` 接下来,我们创建一个 `Service` 类 `DemoServiceClass`,并在其中实现 `onBind()` 方法,返回 `DemoService` 对象。 ```java // DemoServiceClass.java public class DemoServiceClass extends Service { private DemoService demoService; @Override public void onCreate() { super.onCreate(); demoService = new DemoService(); } @Nullable @Override public IBinder onBind(Intent intent) { return demoService; } } ``` 最后,在 `AndroidManifest.xml` 中声明服务。 ```xml <!-- AndroidManifest.xml --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.binderdemo"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <!-- 声明 DemoServiceClass --> <service android:name=".DemoServiceClass" /> <activity android:name=".MainActivity" android:theme="@style/AppTheme.NoActionBar"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest> ``` 现在,我们可以在 `MainActivity` 中创建一个远程服务连接,调用 `add()` 方法并显示结果。 ```java // MainActivity.java public class MainActivity extends AppCompatActivity { private IDemoService demoService; private boolean connected = false; private ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { demoService = IDemoService.Stub.asInterface(iBinder); connected = true; } @Override public void onServiceDisconnected(ComponentName componentName) { demoService = null; connected = false; } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Intent intent = new Intent(this, DemoServiceClass.class); bindService(intent, connection, Context.BIND_AUTO_CREATE); Button button = findViewById(R.id.button); final TextView result = findViewById(R.id.result); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (connected) { try { int a = Integer.parseInt(((EditText) findViewById(R.id.input1)).getText().toString()); int b = Integer.parseInt(((EditText) findViewById(R.id.input2)).getText().toString()); int sum = demoService.add(a, b); result.setText(String.valueOf(sum)); } catch (RemoteException e) { e.printStackTrace(); } } else { result.setText("Service not connected"); } } }); } @Override protected void onDestroy() { super.onDestroy(); unbindService(connection); } } ``` 这就是一个简单的 Android Binder Demo。它演示了如何创建一个远程服务,实现 AIDL 接口并将其绑定到 Activity。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bdmh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值