本文旨在十分钟以内教会你在android 中对aidl的基本使用。作者水平有限,只讲用法,,,,以兹记录
名词解释:
aidl :Android Interface Definition Language,也就是Android接口定义语言
其在android中主要用于进程间通讯,它比广播messager 这些进程间通讯方式更加轻量级,实际上这些进程间通讯方式也是用aidl封装而成,如果需要用到大量的进程间通讯可以考虑使用aidl,有朋友要问如果进程之间有大量的内容需要传递通讯为啥不和并进程呢?这就涉及到我们使用多进程的初衷,一般来说这可能是因为,我们需要保持一个长期的后台任务,将业务拆分为几部分可能是为了分散风险,防止某个业务不正常导致整个应用崩溃等等。
首先按流程来
1.新建项目,创建activity类,同时创建远程service。 mainfest如下:
<service
android:name=".RemoteService"
android:enabled="true"
android:exported="true"
android:process=":remote"
>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android :name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
2.创建两个aidl文件
在目标目录下创建点击创建爱aidl androidstudio 会自动创建一个与当前包名相同但是以aidl打头的aidl包路径,为使独立进程的server能传递消息给原生的activity,需要新建两个aidl文件,我们将其中一个命名为MessageBody.aidl,另一命名为Transim.aidl MessageBody.:
package com.example.aidllearn;
interface MessageBody {
//此接口用来存放从server传过来的消息
void getInfo(String messageToActivity);
}
Transimt:
package com.example.aidllearn;
import com.example.aidllearn.MessageBody;
interface Transim {
//引用了MessageBody类,这个aidl用来传递信息
void toActivity(MessageBody messagebody);
}
在service 中
Transim.Stubstub =new Transim.Stub() {
@Override
public void toActivity(MessageBody messagebody)throws RemoteException {
messageBody = messagebody;
try {
try {
Thread.sleep(3000);
}catch (InterruptedException e) {
e.printStackTrace();
}
Log.e(TAG,"触发返回值调用");
messageBody.getInfo("来自server的消息");
}catch (RemoteException e) {
e.printStackTrace();
Log.e(TAG,"Webserver exception");
}
}
};
然后在 service中的onbind 方法中返回这个new 出来的 stub
另外在activtiy 中
MessageBody.StubmessageBody =new MessageBody.Stub() {
@Override
public void getInfo(String messageToActivity)throws RemoteException {
Log.e(TAG,"MainActivity "+messageToActivity);
}
};
ServiceConnection serviceConnection =new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
try {
mTransim = Transim.Stub.asInterface(service);
mTransim.toActivity(messageBody);
}catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
bindService(intent,serviceConnection,Context.BIND_AUTO_CREATE);
-
当我们在这个远程的service 中调用 messageBody.getInfo("来自server的消息") 这个方法的时候,方法会被回调到activity中的MessageBody.Stub的声明时重写的方法中去,重写的方法的参数就是我们在远程service中调用方法时穿入的值,这样我们就实现了两个进程之间的通信,当然这里只是传递了一个简单的String类型的数据,如果我们想要使用更多高级的封装类作为传递的参数,还需要继承 Parcelable接口来实现,这个下节再讲,
-
总结 一下 ,远程service 中Transim对象 通过 service的onbind和MainActivity中的ServiceConnection被传递到activity中,在activity中 调用了这个Transim对象的toActivity()(这个名字没取好应该是toservice())方法,参数被赋予了一个activity中实现的MessageBody的对象。在Activity中的Transim的方法被调用时,回调到了Service中的实现,这样service通过Transim方法的参数获得了Activity中的MessageBody对象,调用这个对象时又会回调到它在acitivty中的实现。于是实现了完整的传值过程。简单来说就是通过两次相互回调实现了通信.
华丽丽的第二节
这里记录一下使用封装类来传递数据
- 1.首先我们需要创建一个java 的bean 类这里我们将他命名为PackageData, 就像你平时做的那样,然后用它去实现Parcelable接口,如果你使用的是androidstudio 做IDE 那么应该会遇到报错,根据androidstudio 的提示功能自动解决之。最后得到如下的一个java类
package com.example.aidllearn;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Created by HYY on 2018/1/26.
*
* Description:
* Author:HYY
* Update:HYY(2018/1/26 : 14:26)
*/
public class PackageDataimplements Parcelable {
Stringtype1;
Stringtype2;
int type3;
double type4;
public PackageData(String type1, String type2, int type3, double type4) {
this.type1 = type1;
this.type2 = type2;
this.type3 = type3;
this.type4 = type4;
}
protected PackageData(Parcel in) {
type1 = in.readString();
type2 = in.readString();
type3 = in.readInt();
type4 = in.readDouble();
}
public static final CreatorCREATOR =new Creator() {
@Override
public PackageDatacreateFromParcel(Parcel in) {
return new PackageData(in);
}
@Override
public PackageData[]newArray(int size) {
return new PackageData[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(type1);
dest.writeString(type2);
dest.writeInt(type3);
dest.writeDouble(type4);
}
public void readFromParcel(Parcel dest) {
type1=dest.readString();
type2=dest.readString();
type3=dest.readInt();
type4=dest.readDouble();
}
@Override
public StringtoString() {
return "PackageData{" +
"type1='" +type1 +'\'' +
", type2='" +type2 +'\'' +
", type3=" +type3 +
", type4=" +type4 +
'}';
}
}
-
注意: type1 type2 type3 type4 的顺序必须如此,不能乱,因为read和write的时候就是按照这个顺序来的, 如果readFromParcel 是1,2,3,4的顺序,writeToParcel 就必须是1,2,3,4
-
2.然后按类似路径创建一个aidl文件,取相同名字,注意包名 路径必须和java类的一样
PackageData 这个aidl 的内容非常简单只有一个简单的声明
package com.example.aidllearn;
parcelable PackageData;
然后,我们可以在需要传值的aidl中引用这个定义好的PackageData
在 MessageBody.aidl中我们这样写:
package com.example.aidllearn;
import com.example.aidllearn.PackageData;
interface MessageBody {
//此接口用来存放从server传过来的消息
void getInfo(String messageToActivity,inout PackageData packagedata);
}
-
注意:在getInfo方法中 PackageData 类型声明前有个一个 inout的关键字,这个表示 这个数据类型是既可以输入也可以输出的,这里可以是in 也可以 是out 分别表示只能读和只能写但不能为空,但是你如果写了读和写的关键字那么PackageData的实现中就必须要有对应的writeToParcel 方法或者readFromParcel。
-
差不多就这样吧,要过年了,希望家里别吵架,来年找个好媳妇
网友评论