记录一则AIDL案例
以下将通过一个案例具体去介绍通过AIDL来实现跨进程进行通信的方式。具备知识点:bindService启动服务,aidl文件类型 数据类型等
<service
android:name=".ipc.service.RemoteService"
android:process=":remote"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.zxl.service.remote" />
</intent-filter>
</service>
Activity.java代码
findViewById(R.id.btnEnd).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (null != mIMusic){
try {
mIMusic.stop();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
});
private void startService(){
Intent intent = new Intent();
intent.setAction("com.zxl.service.remote");
// 服务所在包名
intent.setPackage("com.example.mydairytestproject");
mActyServiceConn = new ActyServiceConn();
bindService(intent,mActyServiceConn, Context.BIND_AUTO_CREATE);
}
private void stopService(){
if (mActyServiceConn != null){
unbindService(mActyServiceConn);
mActyServiceConn = null;
}
}
private class ActyServiceConn implements ServiceConnection{
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mIMusic = IMusic.Stub.asInterface(service);
// 设置回调方法的方式,让service回调Activity方法
// 记得注册的是 x.Stub()方法
try {
mIMusic.registerStop(new IStopBackAction.Stub() {
@Override
public void stopCallBack(ProgressData progressData) throws RemoteException {
Log.e("返回数据", "stopCallBack: "+progressData.getName() );
if (progressData.getProgress() == 100){
stopService();
ServiceActivity.this.finish();
}
}
});
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
@Override
protected void onResume() {
super.onResume();
Log.e("线程", Thread.currentThread().getId()+"");
}
@Override
protected void onDestroy() {
if (mActyServiceConn != null){
stopService();
}
super.onDestroy();
}
ProgressData实体类
package com.example.mydairytestproject.ipc.IInterface;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Created by apple on 2019-10-31.
* description:
*/
public class ProgressData implements Parcelable {
private int progress;
private String name;
public ProgressData(int progress, String name) {
this.progress = progress;
this.name = name;
}
public int getProgress() {
return progress;
}
public void setProgress(int progress) {
this.progress = progress;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static Creator<ProgressData> getCREATOR() {
return CREATOR;
}
private ProgressData(Parcel in) {
progress = in.readInt();
name = in.readString();
}
public static final Creator<ProgressData> CREATOR = new Creator<ProgressData>() {
@Override
public ProgressData createFromParcel(Parcel in) {
return new ProgressData(in);
}
@Override
public ProgressData[] newArray(int size) {
return new ProgressData[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(progress);
dest.writeString(name);
}
public void readFromParcel(Parcel in) {
progress = in.readInt();
name = in.readString();
}
}
// IMusic.aidl
package com.example.mydairytestproject.ipc.IInterface;
// Declare any non-default types here with import statements
// aidl文件里的变量类型得用parcelable
import com.example.mydairytestproject.ipc.IInterface.IStopBackAction;
// 方法得实现parcelable
interface IMusic {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void play();
void pause();
void stop();
void registerStop(in IStopBackAction iStopBackAction);
}
// IStopBackAction.aidl
package com.example.mydairytestproject.ipc.IInterface;
// Declare any non-default types here with import statements
import com.example.mydairytestproject.ipc.IInterface.ProgressData;
interface IStopBackAction {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void stopCallBack(in ProgressData progressData);
}
// ProgressData.aidl
// 先查创建再修改名字
package com.example.mydairytestproject.ipc.IInterface;
// Declare any non-default types here with import statements
parcelable ProgressData;
Service.java
public class RemoteService extends Service {
public RemoteService() {
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e("线程", Thread.currentThread().getId()+"");
return super.onStartCommand(intent, flags, startId);
}
@Override
public IBinder onBind(Intent intent) {
return new MusicClass();
}
private class MusicClass extends IMusic.Stub {
@Override
public void play() {
Log.e("服务运行", "play: 音乐开启" );
}
@Override
public void pause() {
Log.e("服务运行", "play: 音乐暂停" );
}
@Override
public void stop() {
Log.e("服务运行", "play: 音乐结束" );
// 回调Activity进行传值
if (mIStopBackAction != null){
try {
mIStopBackAction.stopCallBack(new ProgressData(100,"数据"));
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
IStopBackAction mIStopBackAction;
@Override
public void registerStop(IStopBackAction iStopBackAction) {
this.mIStopBackAction = iStopBackAction;
}
}
}
in:参数由客户端设置,或者理解成客户端传入参数值。
out:参数由服务端设置,或者理解成由服务端返回值。
inout:客户端输入端都可以设置,或者理解成可以双向通信。
Proxy.pause():
写入方法参数等,然后调用 transact来发送RPC(远程过程调用)请求,同时当前线程挂起,然后服务端的onTranscat 会根据具体方法的key进行调用进行返回,当前线程继续执行,返回数据。
如果远程方法很耗时,那么不能在UI线程发起远程请求。
参考文章
1、binder c/s交互有个宏观的认识
但这里面最后一张图讲述的,binder通过共享内存的方法存放数据有问题
Android-彻底地理解Binder