为了实现不同间进程通信,我们会使用到AIDL。
由服务端提供服务,客户端通过AIDL链接服务端,以调用服务端对应的功能。
1.服务端
先来看服务端的代码。
我们在Java同级目录下,新建一个aidl文件夹,然后在该文件夹下,新建一个路径和工程包名同样的路径。路径创建完成后,新建AIDL文件。
1.1 AIDL
AIDL文件是Interface类型,我们只要在里面写好对应的方法即可。这里我们做一个简单的加减法运算。
// IMyAidlInterface.aidl
package com.example.aidlserver;
// Declare any non-default types here with import statements
interface IMyAidlInterface {
int add(int num1,int num2);
int getNum();
int minus(int num1,int num2);
}
AIDL文件写好之后,通过IDE进行编译,以便IDE生成对应的文件:app/build/generated/aidl_source_output_dir/debug/compileDebugAidl/out/com/example/aidlserver/IMyAidlInterface.java
1.2 Service
接下来看Service写法:
public class IRemoteService extends Service {
private static final String TAG = "IRemoteService";
private int i = 0;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return iBinder;
}
private IBinder iBinder = new IMyAidlInterface.Stub() {
@Override
public int add(int num1, int num2) throws RemoteException {
return num1 + num2;
}
@Override
public int getNum() throws RemoteException {
return i;
}
@Override
public int minus(int num1, int num2) throws RemoteException {
return num1 - num2;
}
};
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
i++;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.d(TAG, "i: " + i);
}
}
}).start();
return super.onStartCommand(intent, flags, startId);
}
}
创建好service类之后,会要求我们复写onBind方法,该方法返回值是一个IBinder。这个IBinder即是我们通过AIDL文件生成的:new IMyAidlInterface.Stub()
。生成的IBinder文件,传递给onBind方法。
1.3 AndroidMainFest
写好Service ,记得在AndroidMainFest中声明。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.aidlserver">
<application
<service
android:name=".IRemoteService"
android:exported="true">
<intent-filter>
<action android:name="com.example.aidlserver.IRemoteService" />
</intent-filter>
</service>
</application>
</manifest>
这里注意两点
- Service要声明
android:exported
属性为true,否则其他进程无法访问到该服务。 - 要给Service声明一个action,其他进程会通过该action和Service进行链接。Action我们可以选择 包名+Service名
1.4 Activity
AIDL写好了,服务写好了,启动服务即可。
启动服务可在Activity中进行,也可以在Application中进行。
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startService(new Intent(this, IRemoteService.class));
}
}
至此服务端的工作全部完成。
2. 客户端
和服务端一样,客户端下,也要先在和java平级路径下新建一个aidl文件夹,然后建立和服务端一模一样的路径,和服务端一模一样的aidl文件。其实就是把服务端的AIDL文件完全复制过来。
2.1 AIDL
和服务端一模一样
// IMyAidlInterface.aidl
package com.example.aidlserver;
// Declare any non-default types here with import statements
interface IMyAidlInterface {
int add(int num1,int num2);
int getNum();
int minus(int num1,int num2);
}
2.2 Activity
客户端链接AIDL。
首先我们绑定服务的Service。创建一个Intent,设置好Package和Action,Package即服务端的包名,Action即服务端AndroidMainFest中声明的action。在新建一个ServiceConnection,当服务链接成功后,我们实例化AIDL接口文件IMyAidlInterface.Stub.asInterface(service)
。
private IMyAidlInterface iMyAidlInterface;
private ServiceConnection serviceConnection;
private void initEvent() {
serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
iMyAidlInterface = null;
}
};
}
private void bindService() {
Intent intent = new Intent();
intent.setPackage("com.example.aidlserver");
intent.setAction("com.example.aidlserver.IRemoteService");
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
}
实例化iMyAidlInterface后,即可调用对应的方法。
btAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
int res = iMyAidlInterface.add(2, 2);
Log.d(TAG, "add: " + res); //add: 4
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
完整代码:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private Button btAdd, btMinus, btGet;
private IMyAidlInterface iMyAidlInterface;
private ServiceConnection serviceConnection;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
protected void onResume() {
super.onResume();
initView();
initEvent();
bindService();
}
private void initView() {
btAdd = findViewById(R.id.add);
btMinus = findViewById(R.id.minus);
btGet = findViewById(R.id.get_number);
btAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
int res = iMyAidlInterface.add(2, 2);
Log.d(TAG, "add: " + res); //add:4
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
btMinus.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
int res = iMyAidlInterface.minus(9, 2);
Log.d(TAG, "minus: " + res); //minus:7
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
btGet.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
int res = iMyAidlInterface.getNum();
Log.d(TAG, "get: " + res);
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
}
/**
* 实例化AIDL
*/
private void initEvent() {
serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
iMyAidlInterface = null;
}
};
}
/**
* 绑定服务
*/
private void bindService() {
Intent intent = new Intent();
intent.setPackage("com.example.aidlserver");
intent.setAction("com.example.aidlserver.IRemoteService");
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(serviceConnection);
}
}