AIDL(Android Interface Definition Language)是Android接口定义语言的意思,它可以用于让某个Service与多个应用程序组件之间进行跨进程通信,从而可以实现多个应用程序共享同一个Service的功能。实际上实现跨进程之间通信的有很多,
比如广播,Content Provider,但是AIDL的优势在于速度快(系统底层直接是共享内存),性能稳,效率高,一般进程间通信就用它。
既然是跨进程,那必须的有两个应用,一个是service端,一个是client端,然后实现客户端从服务端获取数据。那么我们创建一个服务端,项目结构如图所示:
服务端
在服务端下建立一个MyAIDLService.aidl文件,目录结构为如图所示:
然后,在MyAIDLService下增加一个获取字符串的方法。代码如下:
// MyAIDLService.aidl
package aidl;
// Declare any non-default types here with import statements
interface MyAIDLService {
//获取String数据
String getString();
}
创建完aidl文件以后,我们build一下项目,然后会在build - >generated ->source ->aidl->debug下会生成一个aidl文件,那说明AIDL文件已经编译成功。
接着建立一个MyService类,代码如下:
package com.example.service;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import java.util.Map;
import aidl.MyAIDLService;
public class MyService extends Service {
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent) {
return new Mybind();
}
class Mybind extends MyAIDLService.Stub {
@Override
public String getString() throws RemoteException {
String string = "我是从服务起返回的";
return string;
}
}
}
继承的是MyAIDLService.Stub,是刚刚建立的aidl文件,然后实现我们刚刚的定义的
getString()方法,在这里,我们只是返回一句话,"我是从服务起返回的"
客户端
首先将刚刚在服务端创建的MyAIDLService原封不动的复制到客户端来。(注意:路径要一模一样)。接着我们在客户端的MainActivity中加两个按钮,并且和服务端进行相连,代码如下:
package com.example.administrator.servicetestaidl;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import aidl.MyAIDLService;
public class MainActivity extends Activity {
private Button bindService,unbindService;
private TextView tvData;
private MyAIDLService myAIDLService;
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
myAIDLService = MyAIDLService.Stub.asInterface(service);
try {
String str = myAIDLService.getString();
tvData.setText(str);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
myAIDLService = null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bindService = (Button) findViewById(R.id.bind_service);
unbindService = (Button) findViewById(R.id.unbind_service);
tvData = (TextView) findViewById(R.id.tv_data);
/**
* 绑定服务
*/
bindService.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setAction("com.example.service.MyService");
//从 Android 5.0开始 隐式Intent绑定服务的方式已不能使用,所以这里需要设置Service所在服务端的包名
intent.setPackage("com.example.service");
bindService(intent, connection, BIND_AUTO_CREATE);
}
});
/**
* 解绑服务
*/
unbindService.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
unbindService(connection);
}
});
}
}
这里只需要注意两个地方,一个是绑定服务的时候,因为从 Android 5.0开始 隐式Intent绑定服务的方式已不能使用,所以这里需要设置Service所在服务端的包名
那么这个action是怎么来的呢,我们回来服务端的AndroidManifest.xml,代码如下
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.service">
<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">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".MyService"
>
<intent-filter>
<action android:name="com.example.service.MyService" />
</intent-filter>
</service>
</application>
</manifest>
另一个需要注意的就是获取MyAIDLService对象是通过MyAIDLService.Stub.asInterface(service);这里需要注意一下的。
不过还有一点需要说明的是,由于这是在不同的进程之间传递数据,Android对这类数据的格式支持是非常有限的,
基本上只能传递Java的基本数据类型、字符串、List或Map等。那么如果我想传递一个自定义的类该怎么办呢?这就必须要让这个类去实现Parcelable接口,
并且要给这个类也定义一个同名的AIDL文件。这部分内容并不复杂,而且和Service关系不大,所以就不再详细进行讲解了,感兴趣的朋友可以自己去查阅一下相关的资料。