Android Studio實現遠程服務

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講義》

發佈了30 篇原創文章 · 獲贊 21 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章