您的位置:首页 > 移动开发 > Android开发

Android Service AIDL的学习,传递对象

2017-03-24 18:49 411 查看

Android Service的学习,AIDL传递对象

Service有两种:

1,本地服务(Local Service):用于应用程序内部

2,远程服务(Remote Service):用于android系统内部的应用程序之间 。

使用区别:

本地服务:主要是平时做一些耗时,或者要长时间运行,影响UI线程的时候到到。如,播放音乐,下载等。

远程服务:则用于多应用之间的相互访问。比如做个天气预报的,做个健康数据的。

一开始我们学习使用Service可能会是因为播放多音乐的时候,用户启动了其他Activity这个时候程序要在后台继续播放。我们把MediaPlayer在Local Service里。然后通过bindService()在ServiceConnection里通过IBinder返回一个Service的实例。通过Service实例去操作MediaPlayer的开始和停止等等。例如这样:

Intent intent = new Intent(mContext, TestService.class);

mContext.bindService(intent, mServiceConnection, BIND_AUTO_CREATE);


private ServiceConnection mServiceConnection = new ServiceConnection() {

@Override

public void onServiceConnected(ComponentName name, IBinder service) {

mTestService = ((TestService.MyBinder) service).getService();

}

@Override

public void onServiceDisconnected(ComponentName name) {

mTestService = null;

}

};


当某天用到远程Service的时候,上面这种方式报错了。

将一个普通的Service转换成远程Service其实非常简单,只需要在注册Service的时候将它的android:process属性指定成:remote就可以了。当然这个remote是自定义的。

为什么这里用个“:”呢?

如果被设置的进程名是以一个冒号开头的,则这个新的进程对于这个应用来说是私有的,当它被需要或者这个服务需要在新进程中运行的时候,这个新进程将会被创建。如果这个进程的名字是以小写字符开头的,则这个服务将运行在一个以这个名字命名的全局的进程中,当然前提是它有相应的权限。这将允许在不同应用中的各种组件可以共享一个进程,从而减少资源的占用。

当一个Service被设置为Remote Service时候我们又怎么通信呢?

我们再复习下线程通信与进程通信

线程通信:

- 1)共享变量(内存)

- 2)管道

- 3)handle机制 平时熟悉的runOnUiThread,view.post(Runnable)都是Handle机制

进程通信:

- 1)bind机制(IPC->AIDL)

- 2)Content Provider

- 3)Broadcast

- 4)Intent (有没试过用Intent打开别的应用。。)

这篇文章主要学习AIDL,AIDL是一个缩写,全称是Android Interface Definition Language,也就是Android接口定义语言。关于AIDL是怎么实现跨进程通信的,网上不少资料,关心的小伙伴可以自己查阅。强大的Android Studio为开发者省了很大的工夫。

第一步:创建AIDL:右键New-选择AIDL,输入你的接口名如IMyAidlInterface,点击Finish。

IDE会在src->main目录下新建一个aidl目录与java同级的。

第二步:自定义方法

interface IMyAidlInterface {

void addStudent(inout Student student);

void showTip(String  tip);

}


第三步:Rebuild Project

在项目的 build/generated/source/aidl/debug/包名/下能找到IDE帮你生成的接口

第四步:在Service里返回一个IMyAidlInterface.Sub

“`

@Nullable

@Override

public IBinder onBind(Intent intent) {

return new MyBinder();

}

private class MyBinder extends IMyAidlInterface.Stub{

@Override

public void add(Student student) throws RemoteException {

}
}


第五步:在BindService()


private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mIMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
mIMyAidlInterface = null;
}
};


“`

通过上边的五步我们就拿到了一个IMyAidlInterface实例。这时候可能欢呼了。

当你通过这个接口传一个对象过去的时候,崩了!!!!

查看资料发现AIDL默认支持的数据类型包括:

Java中的八种基本数据类型,包括 byte,short,int,long,float,double,boolean,char。

String 类型。

CharSequence类型。

List类型:List中的所有元素必须是AIDL支持的类型之一,或者是一个其他AIDL生成的接口,或者是定义的parcelable(下文关于这个会有详解)。List可以使用泛型。

Map类型:Map中的所有元素必须是AIDL支持的类型之一,或者是一个其他AIDL生成的接口,或者是定义的parcelable。Map是不支持泛型的。

AIDL传送对象

由于Aidl只支持Java基本类型数据传递,因此是不能直接传递一个复杂类型对象的,所以为了解决这个问题,Android提供了一套机制—-将需要传递的对象序列化,然后在反序列化。

序列化:把Java对象转换为字节序列的过程。

反序列化:把字节序列恢复为Java对象的过程。

第一步:创建一个Student类 implements Parcelable。按提示添加所有方法。(鼠标移动类名ALT+Enter–>add Parcelable implementation)

public class Student implements Parcelable {
int id;
String name;

public Student(int id, String name) {
this.id = id;
this.name = name;
}

protected Student(Parcel in) {
id = in.readInt();
name = in.readString();
}

public static final Creator<Student> CREATOR = new Creator<Student>() {
@Override
public Student createFromParcel(Parcel in) {
return new Student(in);
}

@Override
public Student[] newArray(int size) {
return new Student[size];
}
};

@Override
public int describeContents() {
return 0;
}

@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(id);
dest.writeString(name);
}

public void readFromParcel(Parcel source) {
id = source.readInt();
name = source.readString();
}

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

@Override
public String toString() {
return "Student{" +
"id=" + id +
", name=" + name +
'}';
}

}


第二步:在AIDL目录下里和你类放的路径一样的地方创建一个Student.AIDL

package com.example.yang.testaidl;
parcelable Student;   //parcelable 要小写,网上说的,我也不明真相。


注意目录一定要相同

例如,你在java/包名/beans/下创建的Student 你在aidl/包名/下再创建一个beans文件夹再这个beans下创建Student.aidl。要不然之前定义的IMyAidlInterface引用Student会报错。。。。

第三步:在IMyAidlInterface里加上

import com.example.yang.testaidl.Student;

interface IMyAidlInterface {
void addStudent(inout Student student);
void showTip(String  tip);
}


这里传对象用的是in/out/inout

Parcelable 还有这个方法是隐式的要自己写上来。这样就实现out了

public void readFromParcel(Parcel source) {

id = source.readInt();

name = source.readString();

}

好了。到了这里基本学习完毕。边学边写,有不足之处望批评指正。附Demo

https://github.com/YangKee/TestAIDL.git
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息