实例讲解Android中的AIDL内部进程通信接口使用
首先描述下我们想要实现的内容,我们希望在一个应用中通过点击按钮,去操作另一个进程中应用的音乐播放功能。
如图,我们点击“播放”时,系统就会去远程调用我们提供的一个service(与当前service不是同一个应用哦),然后操作service中的音乐播放,点击“停止”则会终止播放。想要重新播放的话,必须先点“销毁service”,再点播放按钮哦。(至于这里为什么要先点销毁按钮才能播放,完全是为了给大家展示下,远程调用service时,怎么去解绑service)。
在这个例子中,我们用到了一个非常重要的概念,AIDL。
AIDL(android interface definition language)android接口描述语言,其主要的作用就是允许我们在不同的进程间进行通信。
我们都知道每个应用程序都运行在各自的进程中,并且android平台是不允许不同进程间进行直接的对象数据等传递的。如果我们非要进行进程间的通讯,那么我们就必须将我们的数据对象分解成一个个微小的、可以被操作系统理解的数据单元,然后有序的通过进程边界的检查。
如果让我们自己实现,那么这个过程都愁死一批批的程序人了。幸好android,为我们解决了这个问题,这就是AIDL出现的原因了。
AIDL (Android Interface Definition Language)是一种IDL 语言,用于生成可以在Android设备上两个进程之间进行进程间通信(IPC)的代码。如果在一个进程中(例如Activity)要调用另一个进程中(例如Service)对象的操作,就可以使用AIDL生成可序列化的参数。
AIDL IPC机制是面向接口的,像COM或Corba一样,但是更加轻量级。它是使用代理类在客户端和实现端传递数据。
注意:AIDL只支持方法,不能定义静态成员,并且方法也不能有类似public等的修饰符;AIDL运行方法有任何类型的参数和返回值,在java的类型中,以下的类型使用时不需要导入包(import),基本数据类型、String、Map、List.当然为了避免出错,建议只要使用了,就导入包。
使用AIDL的步骤:
服务端(提供服务):
第一步:定义一个*.aidl文件,该文件里是符合aidl语言规范的接口定义,里面定义了外部应用可以访问的方法。当我们保存该文件的时候,eclipse会自动为我们在gen文件夹下生成一个相应的java接口文件。例如RemoteServiceInterface.java
第二步:定义一个自己的service, 并将其注册到androidManifest.xml文件中,例如:
<service android:name="MyRemoteService">
<intent-filter>
<action android:name="cn.com.chenzheng_java.remote"/>
</intent-filter>
</service>
注意这里一定要提供一个intent-filter,我们的客户端进程就是通过该action访问到服务端进程的哦。
我们都知道,在实现自己的service时,为了其他应用可以通过bindService来和我们的service进行交互,我们都要实现service中的onBind()方法,并且返回一个继承了Binder的内部类;在这里,eclipse自动为我们生成的RemoteServiceInterface.java中有一个实现了Binder的内部类,RemoteServiceInterface.Stub。AIDL要求我们,在这里不能再直接去实现Binder类了,而是去实现,AIDL提供给我们的Stub类。 实现stub类的同时,AIDL还要求我们同时实现我们在接口中定义的各种服务的具体实现。至此为止,我们的服务端已经和我们的aidl文件绑定到一起了哦。
客户端:
第一步:客户端要想使用该服务,肯定要先知道我们的服务在aidl文件中到底对外提供了什么服务,对吧?所以,第一步,我们要做的就是,将aidl文件拷贝一份到客户端的程序中(这里一定要注意,包路径要和服务端的保持一致哦,例如服务端为cn.com.chenzheng_java.remote.a.aidl,那么在客户端这边也应该是这个路径)。
第二步:我们都知道,想要和service交互,我们要通过bindService方法,该方法中有一个ServiceConnection类型的参数。而我们的主要代码便是在该接口的实现中。
第三步:在ServiceConnection实现类的onServiceConnected(ComponentName name, IBinder service)方法中通过类似remoteServiceInterface = RemoteServiceInterface.Stub.asInterface(service);方式就可以获得远程服务端提供的服务的实例,然后我们就可以通过remoteServiceInterface 对象调用接口中提供的方法进行交互了。(这里的关键是通过*.Stub.asInterface(service);方法获取一个aidl接口的实例哦)
我们前面在服务端中说过了,必须提供一个intent-filter来匹配请求是否合法,所以我们在客户端访问服务的时候,还必须传递包含了匹配action的Intent哦。
下边整体是代码:
远程服务端:
RemoteServiceInterface.aidl
package cn.com.chenzheng_java.remote;
interface RemoteServiceInterface {
void startMusic();
void stopMusic();
}
MyRemoteService.java
package cn.com.chenzheng_java.remote;
import java.io.IOException;
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.IBinder;
import android.os.RemoteException;
public class MyRemoteService extends Service {
MediaPlayer mediaPlayer;
@Override
public IBinder onBind(Intent intent) {
return new MyBinder();
}
@Override
public void onCreate() {
mediaPlayer = MediaPlayer.create(MyRemoteService.this, R.raw.aiweier);
super.onCreate();
}
private class MyBinder extends RemoteServiceInterface.Stub{
public void startMusic() throws RemoteException {
mediaPlayer.start();
}
public void stopMusic() throws RemoteException {
mediaPlayer.stop();
try {
mediaPlayer.prepare();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
RemoteServiceActivity.java
package cn.com.chenzheng_java.remote;
import android.app.Activity;
import android.os.Bundle;
public class RemoteServiceActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
androidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="cn.com.chenzheng_java.remote"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="8" />
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".RemoteServiceActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name="MyRemoteService">
<intent-filter>
<action android:name="cn.com.chenzheng_java.remote"/>
</intent-filter>
</service>
</application>
</manifest>
客户端:
activity代码:
package cn.com.chenzheng_java;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import cn.com.chenzheng_java.remote.RemoteServiceInterface;
public class LocalServiceActivity extends Activity implements OnClickListener {
String ACTION_NAME = "cn.com.chenzheng_java.remote";
boolean flag = false;
Button button_start ;
Button button_stop ;
Button button_destroy ;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.music);
button_start = (Button) findViewById(R.id.button1);
button_stop = (Button) findViewById(R.id.button2);
button_destroy = (Button) findViewById(R.id.button3);
button_start.setOnClickListener(this);
button_stop.setOnClickListener(this);
button_destroy.setOnClickListener(this);
}
RemoteServiceInterface remoteServiceInterface ;
private class MyServiceConnection implements ServiceConnection{
public void onServiceConnected(ComponentName name, IBinder service) {
remoteServiceInterface = RemoteServiceInterface.Stub.asInterface(service);
try {
Log.i("flag", flag+"");
if(flag){
Log.i("通知", "已经开始唱歌");
remoteServiceInterface.startMusic();
}else{
Log.i("通知", "已经停止唱歌");
remoteServiceInterface.stopMusic();
}
} catch (RemoteException e) {
e.printStackTrace();
}
}
public void onServiceDisconnected(ComponentName name) {
}
}
private MyServiceConnection serviceConnection = new MyServiceConnection();
public void onClick(View v) {
if(v == button_start){
flag = true;
Intent intent = new Intent(ACTION_NAME);
bindService(intent, serviceConnection ,Context.BIND_AUTO_CREATE);
}
if(v == button_stop){
Log.i("通知", "已经点击了停止按钮");
flag = false;
Intent intent = new Intent(ACTION_NAME);
bindService(intent, serviceConnection ,Context.BIND_AUTO_CREATE);
try {
remoteServiceInterface.stopMusic();
} catch (RemoteException e) {
e.printStackTrace();
}
}
if(v == button_destroy){
flag = false;
Intent intent = new Intent(ACTION_NAME);
bindService(intent, serviceConnection ,Context.BIND_AUTO_CREATE);
unbindService(serviceConnection);
}
}
}
music.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent">
<Button android:text="播放" android:id="@+id/button1"
android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
<Button android:text="停止" android:id="@+id/button2"
android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
<Button android:text="销毁service" android:id="@+id/button3"
android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
</LinearLayout>
其他没有粘贴出来的代码都是由系统默认生成的。
AIDL与传递对象
除了上面我们提到的通过service提供音乐播放等类似的服务之外,我们还可以通过service将对象传递回来哦,你知道怎么用吗,先看例子:
当我们点击“获取”时,会从另一个线程的service中获取一个对象,然后将里面的内容读出来。
对于aidl实现以对象的方式交互。主要步骤如下:
服务端:
第一:定义一个实体类,这里是Beauty,定义一个服务接口aidl文件RemoteBeauty.aidl,这里有一点需要注意,我们引用自定义的实体类到aidl中时需要通过import导入包,但是你会发现,即使你导入了包,还是提示找不到,这时候,你要做的是,建一个以实体类名称命名的aidl文件,如Beauty.aidl,在里面添加一句pracelable Beauty。
第二:开始编写Beauty,这里一定要注意,它一定要实现Pracelable接口,该接口是一个序列化的接口,功能和serializable相似,但是功能更加的迅速。此外,在该Beauty内部一定要声明一个public static final Pracelable.Creator<T>CREATOR对象!!除了里面的那个T代表实体类之外,其他的都不准改变哦。
第三:在androidManifest.xml中注册service。并定义好访问该service的action字符串。
客户端:
客户端这边相应的要简单很多,但是要注意的一点是,要将实体类还有aidl文件都拷贝过来哦,而且要保证路径完全一致!!
Beauty.java
package cn.com.chenzheng_java.service;
import android.os.Parcel;
import android.os.Parcelable;
public class Beauty implements Parcelable {
String name ;
int age ;
String sex ;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeInt(age);
dest.writeString(sex);
}
public static final Parcelable.Creator<Beauty> CREATOR = new Creator<Beauty>() {
@Override
public Beauty[] newArray(int size) {
return new Beauty[size];
}
@Override
public Beauty createFromParcel(Parcel source) {
String name = source.readString();
int age = source.readInt();
String sex = source.readString();
Beauty beauty = new Beauty();
beauty.setName(name);
beauty.setAge(age);
beauty.setSex(sex);
return beauty;
}
};
}
RemoteService.java
package cn.com.chenzheng_java.service;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
public class RemoteService extends Service {
@Override
public IBinder onBind(Intent intent) {
Log.i("通知", "执行了OnBind");
return new MyBinder();
}
private class MyBinder extends RemoteBeauty.Stub{
@Override
public Beauty getBeauty() throws RemoteException {
Beauty beauty = new Beauty();
beauty.setName("feifei");
beauty.setAge(21);
beauty.setSex("female");
return beauty;
}}
}
ServiceActivity.java
package cn.com.chenzheng_java.service;
import android.app.Activity;
import android.os.Bundle;
public class ServiceActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
Beauty.aidl
parcelable Beauty;
RemoteBeauty.aidl
package cn.com.chenzheng_java.service;
import cn.com.chenzheng_java.service.Beauty;
interface RemoteBeauty {
Beauty getBeauty();
}
manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="cn.com.chenzheng_java.service"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="8" />
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".ServiceActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- service开始 -->
<service android:name="RemoteService">
<intent-filter>
<action android:name="cn.com.chenzheng_java.remote2"/>
</intent-filter>
</service>
<!-- service结束 -->
</application>
</manifest>
客户端:
ClientActivity.java
package cn.com.chenzheng_java.client;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import cn.com.chenzheng_java.service.Beauty;
import cn.com.chenzheng_java.service.RemoteBeauty;
public class ClientActivity extends Activity implements OnClickListener {
TextView textView ;
Button button ;
String actionName = "cn.com.chenzheng_java.remote2";
RemoteBeauty remoteBeauty;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
textView = (TextView) findViewById(R.id.textView1);
button = (Button) findViewById(R.id.button1);
button.setOnClickListener(this);
}
private class MyServiceConnection implements ServiceConnection{
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i("通知", "链接成功!");
remoteBeauty = RemoteBeauty.Stub.asInterface(service);
try {
Beauty beauty = remoteBeauty.getBeauty();
textView.setText("美女 姓名:"+beauty.getName()+" 年龄:"+beauty.getAge() +" 性别:"+beauty.getSex());
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
MyServiceConnection connection = new MyServiceConnection();
@Override
public void onClick(View v) {
Intent intent = new Intent(actionName);
bindService(intent, connection, Context.BIND_AUTO_CREATE);
}
}
另外Beauty.java 以及RemoteBeauty.aidl都是从服务端系统中拷贝过来的哦。
如果你想你的service在系统开机时自启动。可以在service的androidManifest.xml中加上这样的配置。
<receiver android:name=".StartBroadcastReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
您可能感兴趣的文章:Android使用AIDL方式实现播放音乐案例Android AIDL实现两个APP间的跨进程通信实例Android使用AIDL实现两个App间通信Android应用程序四大组件之使用AIDL如何实现跨进程调用Service使用Android studio创建的AIDL编译时找不到自定义类的解决办法Android 使用【AIDL】调用外部服务的解决方法基于Android AIDL进程间通信接口使用介绍Android程序设计之AIDL实例详解Android Studio创建AIDL文件并实现进程间通讯实例Android多进程间采用AIDL方式进行通信
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341