android服务学习service之AIDL
在android中,不同的应用运行在各自的进程中,互不干扰,一个进程也不能直接的去访问另一个进程的内存空间,因此,进程间通讯,android提供了AIDL这个工具来实现。
AIDL (Android Interface Definition Language) 是一种IDL 语言,用于生成可以在Android设备上两个进程之间进行进程间通信(interprocess communication, IPC)的代码。如果在一个进程中(例如Activity)要调用另一个进程中(例如Service)对象的操作,就可以使用AIDL生成可序列化的参数。AIDL IPC机制是面向接口的,更加轻量级。它是使用代理类在客户端和实现端传递数据。
1.定义AIDL接口
其实,AIDL接口文件和普通的接口文件没有什么区别,只不过它的扩展名是.aidl罢了。因此同其它接口是一样的,只能是接口的声明和方法的声明,它还不能有static成员变量。编辑完成之后,它会自动在gen目录文件夹下自动生成IBinder接口文件。service必须实现这个IBinder接口,那么客户端才能绑定此service然后才能从IBinder中调用方法实现不同进程间的通讯。客户端要想绑定此service并且能顺利的实现通讯,必须要完整的拷贝一份AIDL接口,包括包名以及类名和所需要的其它东东,都必须是完全相同的拷贝,不能有一点差别。(暂时我的理解就是这样)AIDL声明接口的语法很是简单,只是用来描述参数以及返回值,甚至可以是其它的AIDL接口类型。不同的参数类型引用的时候是不一样的。如java数据的基本类(int,long,char,boolean)以及string和charSquence,list,map等是不需要import导入的;如果需要使用其它的AIDL接口以及实现了Parcelable接口的类,它们即使是在同一个包中,也是需要import的。还有就是,对于非java基本数据类型,包括string和charSquence,需要加上方向的指示(in,out,inout),in表示是由客户端设置,out表示服务器端设置,inout表示两端都可以进行设置。
2.创建传递数据Bean--Student类
Student是一个实现了Parcelable接口序列化的类,实现此接口必须要实现以下三个接口:
(1)writeToParcel(Parcel dest, int flags),将序列化存储的数据写入到外部提供的Parcel对象当中,以便读取。
(2)describeContents,网上叫内容接口描述,直接返回0即可,具体是干啥用的,反正我也不知道。
(3)static final Parcelable.Creator 对象 CREATOR,名字是固定的不可以更改。对应的两个接口分别是
createFromParcel(Parcel source):实现从source中创建出Bean实例的功能,如new Student(source)
newArray(int size):创建一个长度为size的类型为Bean的数组,如new Student[size]
(4)此外,既然数据能存了,还得必须能读出来啊,因此方法readFromParcel(Parcel in)这是可以要有的,读取
的顺序与写入的顺序是一样一样的,不能有错。Student类如下:
package com.dandy.AIDL;import android.os.Parcel;import android.os.Parcelable;public class Student implements Parcelable {public static final int SEX_MALE = 1;public static final int SEX_FEMALE = 2;public int sno;public String name;public int sex;public int age;public Student() {}public static final Parcelable.Creator<Student> CREATOR = new Parcelable.Creator<Student>() {@Overridepublic Student createFromParcel(Parcel source) {return new Student(source);}@Overridepublic Student[] newArray(int size) {return new Student[size];}};private Student(Parcel in) {readFromParcel(in);}@Overridepublic int describeContents() {return 0;}@Overridepublic void writeToParcel(Parcel dest, int flags) {dest.writeInt(sno);dest.writeString(name);dest.writeInt(sex);dest.writeInt(age);}public void readFromParcel(Parcel in) {sno = in.readInt();name = in.readString();sex = in.readInt();age = in.readInt();}}
(5)实体类Student创建完成之后,需要创建Student.aidl文件,注意的是,这里的parcelable与实现的Parcelable是不一样的,
前者首字母p是小写,后者首字母P是大写,千万不要搞混咯。代码如下:
package com.dandy.AIDL;parcelable Student;简单得很,就一句话就完事了。
3.创建AIDL接口
新建包:com.dandy.AIDL,然后在包中新建名为IMyService.aidl和IMyServiceResult.aidl的接口。如下:
package com.dandy.AIDL;interface IMyServiceResult{void backResult(int result);}
package com.dandy.AIDL;import com.dandy.AIDL.Student;import com.dandy.AIDL.IMyServiceResult;interface IMyService{List<Student> getStudent();int addStudent(in Student student);void result(in IMyServiceResult resultService);}
IMyService是主体,既是让我们外部实现调用的,而IMyServiceResult是作为IMyService中的一个方法中的参数。
4.实现接口
创建一个服务类来实现刚才定义的IMyService.aidl接口,代码如下:
package com.dandy.service;import java.util.ArrayList;import java.util.List;import com.dandy.AIDL.IMyService;import com.dandy.AIDL.IMyServiceResult;import com.dandy.AIDL.Student;import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.os.RemoteException;public class MyService extends Service{private List<Student> mStudents = new ArrayList<Student>();private static final String PACKAGE_SAYHI = "com.example.aidlclient"; private boolean mCanRun = true; private int counter = 0;private IMyServiceResult resultService;private final IMyService.Stub mBinder = new IMyService.Stub() {@Overridepublic List<Student> getStudent() throws RemoteException {synchronized (mStudents) {return mStudents;}}@Overridepublic int addStudent(Student student) throws RemoteException {if(!mStudents.contains(student)){ mStudents.add(student); return 1;}return 0;}@Overridepublic void result(IMyServiceResult resultService)throws RemoteException {MyService.this.resultService = resultService;};/** *权限验证 */@Overridepublic boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws RemoteException {String packageName = null;String packages[] = MyService.this.getPackageManager().getPackagesForUid(getCallingUid()); if(packages != null && packages.length > 0) { packageName = packages[0]; } if(!PACKAGE_SAYHI.equals(packageName)){ return false; } return super.onTransact(code, data, reply, flags); }};@Overridepublic void onCreate() {Thread thread = new Thread(null,new ServiceWorkerTest(),"BackgroundServiceWorkerTest");thread.start();for (int i = 1; i < 6; i++) { Student student = new Student(); student.name = "student:" + i; student.age = i * 5; mStudents.add(student); } };@Override public void onDestroy(){ mCanRun = false; super.onDestroy(); } @Overridepublic IBinder onBind(Intent intent) {return mBinder;}class ServiceWorkerTest implements Runnable {@Overridepublic void run() {while (mCanRun) {if(resultService != null){try {resultService.backResult(counter);} catch (RemoteException e) {e.printStackTrace();}}counter++;try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}}}
在这里会看到一个IMyService.Stub类,这个类继承自IBinder类,也就是说这个MyService和普通的service 类没有区别,只不过这个这个类是返回的实现AIDL的IBinder对象。
(5)客户端获取,代码如下:
private final ServiceConnection mServiceConnection = new ServiceConnection() {@Overridepublic void onServiceDisconnected(ComponentName name) {mIMyService = null;}@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {mIMyService = IMyService.Stub.asInterface(service);}};MyService的绑定以及解绑与普通的Service没有区别。
(6)方法的调用
findViewById(R.id.get).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {try {Student student = mIMyService.getStudent().get(0);Log.i("TAG", "----->student:"+student.toString());} catch (Exception e) {e.printStackTrace();}}});findViewById(R.id.add).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Student student = new Student();student.age = 100;student.name = "dandy";student.sex = Student.SEX_MALE;try {int result = mIMyService.addStudent(student);Log.i("TAG", "------>result:"+result);} catch (RemoteException e) {e.printStackTrace();}}});findViewById(R.id.result).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {try {mIMyService.result(new IMyServiceResult.Stub() {@Overridepublic void backResult(int result) throws RemoteException {Log.i("TAG", "--------------->result:"+result);}});} catch (RemoteException e) {e.printStackTrace();}}});
(7)AndroidManifest.xml中service配置
<service android:name="com.dandy.service.MyService" android:process=":remote" android:exported="true"> <intent-filter > <category android:name="android.intent.category.DEFAULT" /> <action android:name="com.dandy.service.MyService"/> </intent-filter> </service>
android:process=":remote",代表在应用程序里,当需要该service时,会自动创建新的进程。而如果是android:process="remote",
没有“:”分号的,则创建全局进程,不同的应用程序共享该进程。
注:以上内容结合了部分网络上资源内容,还望原著见谅!
资源文件下载。点击此处!
更多相关文章
- 一定是我打开的姿势不对——Android下使用kill命令杀死指定进程
- Android使用AIDL跨进程数据共享
- Android listview中嵌套Checkbox的布局文件
- AIDL实现Android的进程通信
- android studio导入 so ,jar 文件。
- IDA动态调试Android的DEX文件
- android反编译apk文件
- android工程下的文件资源类型
- linux内核启动android文件系统过程分析