AndroidStudio实现远程服务
(1) 什么是远程服务
(2) Android实现原理
(3) 实例讲解
一、什么是远程服务
简单来说就是:从一个进程调用另一个进程中的服务程序。
二、Android实现原理
如图1所示:
图1 android远程服务示意图
(1) 客户端一般是自定义的Activity,通过bindService()发起服务绑定
(2) 服务端,通过onBind()响应绑定请求,并返回共接口的Binder
(3) 客户端将接收到的Binder转换成接口对象ISecondary,好比获得了远程对象通信接口的应用
(4) 由于客户端与服务端定义了相同的接口(AIDL文档相同),所以可以通过(3)中的ISecondary对象调用接口中的方法,如此一来访问远程服务的方法如同访问本地对象的方法一般
(5) 通过接口实现代码将请求传给服务对象
(6) 服务代码调用自己的方法
二、实例讲解
分别创建两个Android Application,ServiceClient和ServicServer
服务端:ServicServer
创建接口文件:IParams.aidl
import com.zdang.mservice.Pet;
import com.zdang.mservice.Person;
interface IParams {
List<Pet> getPetByOwner(in Person owner);
}
该接口中包含了自定义的Object Person和Pet,所以必须为他们分别创建Person.aidl 和Pet.aidl,内容如下
Person.aidl
package com.zdang.mservice; parcelable Person;
package com.zdang.mservice; parcelable Pet;
如果不创建上面两个文件则编译时会报错:找不到定义的类
然后是自定义的Person.java和Pet.java
public class Person implements Parcelable{
private int id;
private String petName;
public Person(){
}
public Person(int id, String name){
super();
this.id=id;
this.petName=name;
}
protected Person(Parcel in) {
this.id = in.readInt();
this. petName = in.readString();
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getPetName() {
return petName;
}
public void setPetName(String petName) {
this.petName = petName;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(id);
dest.writeString(petName);
}
public static final Creator<Person> CREATOR = new Creator<Person>() {
@Override
public Person createFromParcel(Parcel in) {
return new Person(in);
}
@Override
public Person[] newArray(int size) {
return new Person[size];
}
};
@Override
public boolean equals(Object obj) {
if(this==obj){
return true;
}
if(obj==null){
return false;
}
if(getClass()!=obj.getClass()){
return false;
}
Person other= (Person) obj;
if(petName ==null){
if(other.petName!=null) return false;
}else if(!petName.equals(other.petName)) {
return false;
}
return true;
}
@Override
public int hashCode() {
final int prime=31;
int result=1;
result=prime*result+((petName==null)?0: petName.hashCode());
return result;
}
}
Pet.java与Person.java类似,需要指出的是:自定义的类必须要实现串行化接口Parcelable否则不能够作为参数传递,该接口的实现可参照代码。
服务类:MyService
public class MyService extends Service{
private static Map<Person,List<Pet>> paramList=new HashMap<Person,List<Pet>>();
private static List<Pet> pet02;
static {
List<Pet> pet01=new ArrayList<Pet>();
pet01.add(new Pet("duck","black"));
pet01.add(new Pet("chicken","golden"));
paramList.put(new Person(1,"tom"),pet01);
pet02=new ArrayList<Pet>();
pet02.add(new Pet("pig","white"));
pet02.add(new Pet("tiger","yellow"));
paramList.put(new Person(2,"will"),pet02);
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public IBinder onBind(Intent intent) {
return iParams;
}
IParams.Stub iParams=new IParams.Stub(){
@Override
public IBinder asBinder() {
return null;
}
@Override
public List<Pet> getPetByOwner(Person owner) throws RemoteException {
return paramList.get(owner);
}
};
@Override
public void onDestroy() {
super.onDestroy();
}
}
onBind()放回一个IParam.stub对象供客户端调用。
AndroidManifest.xml
<service
android:name=".UsbService"
android:process=":remote"
android:exported="true">
<intent-filter>
<action android:name="com.zdang.service.mservice"/>
</intent-filter>
</service>
Android:process=”:remote”声明该服务为远程服务
Android:name=”com.zdang.service.mservice”设置该服务的action
客户端:ServiceClient
private void startBinderService(){
if(mService==null){
Intent intent=new Intent();
intent.setAction("com.zdang.service.usbservice");
bindService(intent,serviceConnection,Context.BIND_AUTO_CREATE);
}
private ServiceConnection serviceConnection=new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mService= IParams.Stub.asInterface(service);
if(mService==null){
Toast.makeText(getApplicationContext(),"mService is null!",Toast.LENGTH_LONG).show();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
通过调用bindService(intent,serviceConnecttion,Context.BIND_AUTO_CREATE),与后台服务绑定,其中intent.setAction(“com.zdang.service.mservice”);必须与服务端设置action保持一致,否则找不到服务。
注意事项:
1) AIDL文件写完后ReBuild工程会自动生成接口实现文件
2) 客户端与服务端的接口必须保持一致:包括内容、包名、所有依赖的自定义对象
3)aidl中自定义的参数对象一定要为其单独定义xxx.aidl 并写入parcelabel xxx。
4) 自定义的参数对象必须实现parcelabel接口
此外在Android studio上如果编译出错可在build.grade(module)的android节点下添加
sourceSets {
main {
manifest.srcFile 'src/main/AndroidManifest.xml'
java.srcDirs = ['src/main/java', 'src/main/aidl']
resources.srcDirs = ['src/main/java', 'src/main/aidl']
aidl.srcDirs = ['src/main/aidl']
res.srcDirs = ['src/main/res']
assets.srcDirs = ['src/main/assets']
}
}