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'] } }
註明:本文大部分內容摘自《瘋狂android講義》