最近看《安卓开发艺术探索》,降到binder,Messenger,AIDL的相关东西,主要用于IPC处理,学习了一个小样例,总结AIDL基础用法和注意问题。
视频来源:http://www.imooc.com/video/11193
样例内容:客户端做一个简易计算器,将输入传给服务端,服务端进行计算回传给客户端作为结果。客户端和服务端分别属于两个进程(可以在一个APP中,声明服务端在另一个进程中运行,自行百度,这里简单起见直接声明在两个APP中)。服务端定义countAIDL接口包含计算的方法add,和实现计算接口的服务IRemoteService。客户端要在相同包名下定义countAIDL接口(这点还有点没想明白。。),并在Activity初始化时连接服务得到countAIDL对象,在按钮点击事件中调用方法获取计算结果。
实现过程:
工程结构图:
首先服务端(app):
新建aidl文件夹,定义接口:
// countAIDL.aidl
package com.example.a65192.aidltest;
// Declare any non-default types here with import statements
interface countAIDL {
int add(int num1,int num2);
}
自定义服务类IRemoteService:
package com.example.a65192.aidltest;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import android.util.Log;
/**
* Created by 65192 on 2017/8/30.
*/
public class IRemoteService extends Service {
private IBinder iBinder=new countAIDL.Stub(){
@Override
public int add(int num1, int num2) throws RemoteException {
Log.v("IRemoteService:","num1=="+num1+"&num2=="+num2);
return num1+num2;
}
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
return iBinder;
}
}
客户端:
同样声明aidl文件,见工程目录。
Mainactivity中:
package com.example.appclient;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.databinding.DataBindingUtil;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import com.example.a65192.aidltest.countAIDL;
import com.example.appclient.databinding.ActivityMainBinding;
public class MainActivity extends AppCompatActivity {
ActivityMainBinding binding;
countAIDL countAidl;
ServiceConnection conn=new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
countAidl=countAIDL.Stub.asInterface(service);
Log.i("bind:","绑定成功");
}
@Override
public void onServiceDisconnected(ComponentName name) {
countAidl=null;
Log.i("bind:","绑定失败");
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding= DataBindingUtil.setContentView(this,R.layout.activity_main);
// setContentView(R.layout.activity_main);
bindService();
}
public void clickCount(View view) throws RemoteException {
binding.result.setText(countAidl.add(Integer.parseInt(binding.num1.getText().toString()),Integer.parseInt(binding.num2.getText().toString()))+"");
}
private void bindService() {
Log.i("bind:","1");
Intent intent=new Intent();
intent.setComponent(new ComponentName("com.example.a65192.aidltest","com.example.a65192.aidltest.IRemoteService"));
bindService(intent,conn, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(conn);
}
}
对应xml:
<?xml version="1.0" encoding="utf-8"?>
<layout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:id="@+id/num1"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="+"/>
<EditText
android:id="@+id/num2"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="="/>
<EditText
android:id="@+id/result"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/count"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="计算"
android:onClick="clickCount"
/>
</LinearLayout>
</layout>
这里调试的时候主要bug是要在服务端的Manifest.xml中声明service,并设置exported属性为true,这样外部进程才可访问该服务。如下:
<service android:name=".IRemoteService"
android:exported="true">
</service>
工程里也用了databinding的一些东西,自行百度。