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
}
该接口中包含了自定义的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 CreatorCREATOR = new Creator () { @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,List > paramList=new HashMap,List >() ; private static Listpet02; static { List pet01= new ArrayList() ; pet01.add(new Pet("duck","black")); pet01.add(new Pet("chicken","golden")); paramList.put(new Person(1,"tom"),pet01); pet02=new ArrayList() ; 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 ListgetPetByOwner(Person owner) throws RemoteException { return paramList.get(owner); } }; @Override public void onDestroy() { super.onDestroy(); } }
onBind()放回一个IParam.stub对象供客户端调用。
AndroidManifest.xml
android:name=".UsbService"
android:process=":remote"
android:exported="true">
android:name="com.zdang.service.mservice"/>
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'] } }
注明:本文大部分内容摘自《疯狂android讲义》