AIDL服務調用簡單實踐

前言

最近在看AMS中的源碼,發現原理是AIDL進行IPC通訊,特此將基礎回顧下,編寫了一個簡單的DEMO,方便理解。

客戶端開啓和關閉遠程服務

創建兩個App

  • ServiceApp:包含遠程服務
  • ClientApp:調用遠程服務

ServiceApp

  • 創建RemoteAppService服務
public class RemoteAppService extends Service {

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }


    @Override
    public void onCreate() {
        super.onCreate();
        System.out.println("RemoteAppService onCreate....");
    }


    @Override
    public void onDestroy() {
        super.onDestroy();
        System.out.println("RemoteAppService onDestroy....");
    }
}
  • 註冊服務
<service  
	android:name="com.martin.lib.ipc.remote.RemoteAppService"
	android:enabled="true"
	android:exported="true"
/>

ClientApp

  • 調用ServiceApp的RemoteAppService服務
/**
* 包名爲應用程序的報名
*/
private static final String PKG = "com.optimize.lib.ipc";
/**
* 需要啓動的服務的全路徑名稱
*/
private static final String CLS = "com.martin.lib.ipc.remote.RemoteAppService";
Intent intent = new Intent();
intent.setComponent(new ComponentName(PKG,CLS));
findViewById(R.id.open_btn).setOnClickListener(v -> {
    startService(intent);
});
findViewById(R.id.close_btn).setOnClickListener(v -> {
    stopService(intent);
});

遠程服務調用在5.0以後,需要使用顯示調用。

  • 查看日誌
    在這裏插入圖片描述

綁定跨進程服務

  • bindService:綁定服務
  • unbindService:解綁服務

ClientApp

   findViewById(R.id.bindRemoteServiceBtn).setOnClickListener(v -> {
            bindService(intent,this, Service.BIND_AUTO_CREATE);
        });
        findViewById(R.id.unBindRemoteServiceBtn).setOnClickListener(v -> {
            unbindService(this);
        });
  • 查看日誌
    在這裏插入圖片描述

AIDL

AIDL是Android中編寫服務向外暴露接口的一種描述語言,服務在外提供接口時需要使用AIDL將接口編寫,Android會自動將AIDL文件轉換爲Java文件,若客戶端需要進行接口調用,只需拷貝遠程的AIDL文件生成Java代碼後使用即可。

ServiceApp

  • 定義IRemoteServiceBinder的AIDL文件
// IRemoteServiceBinder.aidl
package com.optimize.lib.ipc;

// Declare any non-default types here with import statements

// IRemoteServiceBinder.aidl
package com.optimize.lib.ipc;

// Declare any non-default types here with import statements

interface IRemoteServiceBinder {
    /**
      * 遠程登錄
      */
    boolean login(String user,String password);
}


  • 在使用Service中使用,定義的AIDL生成的Java類,並在onBind中進行回傳。
public class RemoteAppService extends Service {

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
       return new IRemoteServiceBinder.Stub() {

            @Override
            public boolean login(String data) throws RemoteException {
                System.out.println("user:"+user+",password"+password);
            }
        };
    }
}

ClientApp進行遠程調用

  • 創建AIDL文件夾,將將遠程的AIDL文件進行復制到aidl文件夾中,注意文件名稱和報名路徑必須和ServiceApp完全相同。

在這裏插入圖片描述

  • 代碼中進行賦值和調用
IRemoteServiceBinder binder = null;

    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        //這裏不能做強制類型的轉換,因爲他們的內存地址是不一樣的,所以修改一下. binder = (IRemoteServiceBinder) service;
        //正確寫法
        binder = IRemoteServiceBinder.Stub.asInterface(service);
    }

注意,雖然拷貝了相同的文件,但是他們在內存中的地址是不一樣的,所以不能進行強轉,此時我們需要IRemoteServiceBinder.Stub.asInterface(service);方法來進行類型轉換。

  • 調用
findViewById(R.id.syncDataBtn).setOnClickListener(v -> {
            if (binder != null) {
                try {
                    EditText userNameEdt = findViewById(R.id.userNameEdt);
                    EditText passwordEdt = findViewById(R.id.passwordEdt);
                    boolean isSuccess = binder.login(userNameEdt.getText().toString(),
                            passwordEdt.getText().toString());
                    if (isSuccess){
                        System.out.println("login success");
                    }else {
                        System.out.println("login failure");
                    }
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });
  • 查看結果
    在這裏插入圖片描述

參考文章

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章