1:Binder原理解析
1: 这是一种比startService更复杂的启动方式,同时使用这种方式启动的service也能完成更多的事情,
2: 比如其他组件可向其发送请求,接受来自它的响应,甚至通过它来进行IPC等等。我们通常将绑定它的组件称为客户端,而称它为服务端。
3:如果要创建一个支持绑定的service,我们必须要重写它的onBind()方法。这个方法会返回一个IBinder对象,它是客户端用来和服务器进行交互的接口。
而要得到IBinder接口,我们通常有三种方式:继承Binder类,使用Messenger类,使用AIDL。
上面概念如此复杂,下来跟着我来一步一步解析Binde诞生过程。
举个例子:
使用Binder实现一个客户端连接服务端查询学生成绩的例子。
1.服务端提供查询服务
public class GradeService extends Service {
public static final int REQUEST_CODE=1000;
private final Binder mBinder = new Binder() {
@Override
protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException {
if (code == REQUEST_CODE) {
// 1 先匹配客户端的请求码,然后从data读出数据
String name = data.readString();
// 根据姓名查询学生成绩并将成绩写入到返回数据
int studentGrade = getStudentGrade(name);
if (reply != null)
// 2. 从reply向客户端写返回值,这时唤醒了客户端。
reply.writeInt(studentGrade);
// 3. 处理完成
return true;
}
return super.onTransact(code, data, reply, flags);
}
// 根据姓名查询学生成绩
public int getStudentGrade(String name) {
return StudentMap.getStudentGrade(name);
}
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
<service
android:name="com.zhpan.sample.binder.server.GradeService"
android:process=":server">
<intent-filter>
<action android:name="android.intent.action.server.gradeservice" />
</intent-filter>
</service>
2.客户端连接服务查询成绩
public class BinderActivity extends AppCompatActivity {
// 远程服务的Binder代理
private IBinder mRemoteBinder;
private final ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
// 获取远程服务的Binder代理
mRemoteBinder = iBinder;
// 1:从对象池拿到可复用的对象(享元模式)
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
int grade = 0;
// 2. 往 data里面写数据,作为请求参数
data.writeString(name);
try {
if (mRemoteBinder == null) {
throw new IllegalStateException("Need Bind Remote Server...");
}
// 3. 拿到了服务端的IBinder句柄,调用 transact ,并约定请求码,其中第四个参数
flag = 0 表示同步调用,1 表示表示异步调用
mRemoteBinder.transact(REQUEST_CODE, data, reply, 0);
//4 从服务端已经获取到内容了,直接从 relpy中读取
grade = reply.readInt();
} catch (RemoteException e) {
e.printStackTrace();
}
return grade;
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
mRemoteBinder = null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_binder);
// 绑定服务
findViewById(R.id.btn_bind_service).setOnClickListener(view -> bindGradeService());
}
// 绑定远程服务
private void bindGradeService() {
String action = "android.intent.action.server.gradeservice";
Intent intent = new Intent(action);
intent.setPackage(getPackageName());
bindService(intent, mServiceConnection, BIND_AUTO_CREATE);
}
2:Binder原理剖析2
3:Binder原理图
3.1 Binder总结
1:通过这个例子,我们可以看出,Binder机制使用了
Parcel来序列化数据
,客户端在主线程调用了
transact来请求
(Parcel data传参),服务端在
Binder线程
调用
onTransact来响应
(Parcel reply回传结果)。
2: 由于我们的flags传入的是
0
同步调用,可以试着在服务端onTransact里sleep几秒,会发现客户端需要几秒后才能打印出返回值。所以如果服务端需要进行耗时操作,客户端则需要在子线程里进行binder调用。
3:默认情况下,binder传递数据是同步的,
transact(int code, Parcel data, Parcel reply, int flags)
你可以定义oneway关键字来实现异步
mRemote.transact(int code, Parcel data, Parcel reply, android.os.IBinder.FLAG_ONEWAY);