Android--AIDL使用

AIDL介紹

我們通常比較熟悉Android應(yīng)用程序中進(jìn)行跨進(jìn)程訪(fǎng)問(wèn)的組件BroadcastReceiver和ContentProvider,另外一個(gè)Android應(yīng)用程序組件Service也可以,這種可以跨進(jìn)程訪(fǎng)問(wèn)的服務(wù)稱(chēng)為AIDL服務(wù)。

AIDL (Android Interface Definition Language)是 Android 提供的一種機(jī)制,允許通過(guò)跨進(jìn)程的接口實(shí)現(xiàn)不同應(yīng)用或進(jìn)程之間的通信。

AIDL 的基本原理

在 Android 中,每個(gè)應(yīng)用運(yùn)行在自己的獨(dú)立進(jìn)程中。當(dāng)需要跨進(jìn)程進(jìn)行通信時(shí),應(yīng)用間的對(duì)象無(wú)法直接傳遞和共享,必須通過(guò) AIDL 接口進(jìn)行通信。AIDL 會(huì)自動(dòng)生成接口代碼來(lái)處理復(fù)雜的數(shù)據(jù)類(lèi)型和方法調(diào)用,從而使兩個(gè)進(jìn)程可以在不直接共享內(nèi)存的情況下進(jìn)行數(shù)據(jù)交換。

AIDL 使用類(lèi)似于 Java 接口的語(yǔ)法,并定義一個(gè)接口來(lái)描述客戶(hù)端和服務(wù)端之間的交互方法。Android 系統(tǒng)通過(guò)這一接口來(lái)生成代理類(lèi)和實(shí)際實(shí)現(xiàn)類(lèi),從而實(shí)現(xiàn)跨進(jìn)程調(diào)用。

AIDL 的基本工作流程
  1. 定義 AIDL 接口:在服務(wù)端應(yīng)用中,定義一個(gè) AIDL 文件,描述客戶(hù)端和服務(wù)端之間的通信接口。
  2. 生成 Java 接口:使用 AIDL 文件,Android 編譯器會(huì)自動(dòng)生成對(duì)應(yīng)的 Java 接口代碼。該代碼會(huì)包含一個(gè)接口類(lèi)(Stub 類(lèi))和一個(gè)客戶(hù)端代理類(lèi)(Proxy 類(lèi))。
  3. 實(shí)現(xiàn)接口:服務(wù)端實(shí)現(xiàn)生成的接口方法,客戶(hù)端通過(guò)代理類(lèi)調(diào)用這些方法。
  4. 綁定服務(wù):客戶(hù)端通過(guò) bindService() 將服務(wù)綁定到自己的進(jìn)程,從而可以通過(guò) AIDL 接口調(diào)用服務(wù)端的功能。

AIDL使用

通常一個(gè)apk就是一個(gè)進(jìn)程,要實(shí)現(xiàn)進(jìn)程間通信需要兩個(gè)進(jìn)程,一個(gè)作為服務(wù)端,一個(gè)作為客戶(hù)端,服務(wù)端來(lái)定義AIDL接口,寫(xiě)接口實(shí)現(xiàn),客戶(hù)端可以調(diào)用服務(wù)端的AIDL接口實(shí)現(xiàn)功能。

注意:實(shí)現(xiàn)AIDL需要系統(tǒng)權(quán)限,準(zhǔn)備工作需要在兩個(gè)進(jìn)程中都添加系統(tǒng)權(quán)限和系統(tǒng)簽名。

這里創(chuàng)建一個(gè)Project工程,其中的app包名設(shè)置為com.example.aidlserver,作為AIDL的服務(wù)端,然后新建一個(gè)module作為AIDL的客戶(hù)端,包名設(shè)置為com.example.aidlclient

AIDL服務(wù)端

1. 定義AIDL服務(wù)接口

先在com.example.aidlserver中創(chuàng)建AIDL接口,選中包名右鍵新建AIDL,接口名為IAidlServer。

create.png
serverAidl.png

在IAidlServer.aidl中增加add()和minus()兩個(gè)功能接口。

<app/main/aidl/com.example.aidlserver/IAidlServer.aidl>

interface IAidlServer {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);

    int add(int num1, int num2);
    int minus(int num1, int num2);
}

定義好AIDL接口后先編譯一遍,編譯之后Android會(huì)自動(dòng)生成AIDL的服務(wù)接口,其中實(shí)現(xiàn)了stub、proxy的class,以及TRANSACTION的code,用來(lái)通信處理。

sever實(shí)現(xiàn).png

2. 實(shí)現(xiàn)AIDL服務(wù)接口

在com.example.aidlserver中創(chuàng)建Service服務(wù)類(lèi),實(shí)現(xiàn)AIDL中的功能接口。

<app/main/java/com.example.aidlserver/AidlServer.java>

public class AidlServer  extends Service {

    private static final String TAG = "=== AidlServer ===";

    // 服務(wù)實(shí)體
    private final IAidlServer.Stub mStub = new IAidlServer.Stub() {
        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
            Log.d(TAG, "basicTypes ");
        }

        @Override
        public int add(int num1, int num2) throws RemoteException {
            int sum = num1 + num2;
            Log.d(TAG, "add sum = " + sum);
            return sum;
        }

        @Override
        public int minus(int num1, int num2) throws RemoteException {
            int differ = num1 - num2;
            Log.d(TAG, "minus differ = " + differ);
            return differ;
        }
    };

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate ");
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "onStart ");
        return mStub;
    }
}

3. 靜態(tài)注冊(cè)Service

在A(yíng)ndroidManifest.xml中靜態(tài)注冊(cè)AIDL的實(shí)現(xiàn)類(lèi),將Service對(duì)外暴露,這樣客戶(hù)端才能訪(fǎng)問(wèn)。

<app/main/AndroidManifest.xml>

        <service android:name=".AidlServer"
            android:enabled="true"
            android:exported="true">
            <!-- enable:ture設(shè)置可用   exported:ture對(duì)外暴露 -->
            <intent-filter>
                <action android:name="com.example.aidlserver.aidlserver"/>
            </intent-filter>
        </service>
AIDL客戶(hù)端

1. 復(fù)制服務(wù)端的AIDL服務(wù)接口

把服務(wù)端的AIDL以及包目錄完整的拷貝到客戶(hù)端的mian目錄下,讓Client和Server的服務(wù)對(duì)象對(duì)等。

clientAidl.png

AIDL接口復(fù)制到客戶(hù)端之后編輯aidlclient模塊,在客戶(hù)端的build中生成服務(wù)接口。

client.png

2. 在客戶(hù)端綁定服務(wù)使用接口

首先在客戶(hù)端的MainActivity頁(yè)面中添加兩個(gè)按鈕,分別用來(lái)觸發(fā)實(shí)現(xiàn)add和minus功能。

然后在MainActivity.java中調(diào)用AIDL接口實(shí)現(xiàn)功能。

(1)綁定AIDL服務(wù)。
(2)調(diào)用接口。
(3)解綁AIDL服務(wù)。

<aidl/main/java/com.example.aidlserver/MainActivity.java>

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "=== AidlClient ===";

    private IAidlServer aidlServer;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    protected void onResume() {
        super.onResume();

        // 綁定 AidlService
        Intent intent = new Intent();
        intent.setAction("com.example.aidlserver.aidlserver");
        intent.setPackage("com.example.aidlserver"); // server's package name
        boolean isBound = bindService(intent, connection, BIND_AUTO_CREATE);
        Log.d(TAG, "綁定服務(wù) bindService result: " + isBound);

        initView();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        // 解綁 AidlService
        unbindService(connection);
        Log.d(TAG, "解綁服務(wù) unbindService finished !");
    }

    private void initView(){

        // add
        findViewById(R.id.add).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Log.d(TAG, "add onClick : " + (aidlServer == null));

                if (aidlServer != null) {
                    try {
                        int sum = aidlServer.add(12, 34);
                        Log.d(TAG, "sum = " + sum);
                        Toast.makeText(MainActivity.this, String.valueOf(sum), Toast.LENGTH_SHORT).show();
                    } catch (RemoteException e) {
                        e.printStackTrace();
                        Log.e(TAG, "AidlServer.add error : " + e);
                    }
                }
            }
        });

        // minus
        findViewById(R.id.minus).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Log.d(TAG, "differ onClick : " + (aidlServer == null));

                if (aidlServer != null) {
                    try {
                        int differ = aidlServer.minus(34, 12);
                        Log.d(TAG, "differ = " + differ);
                        Toast.makeText(MainActivity.this, String.valueOf(differ), Toast.LENGTH_SHORT).show();
                    } catch (RemoteException e) {
                        e.printStackTrace();
                        Log.e(TAG, "aidlService.minus error : " + e);
                    }
                }
            }
        });
    }

    private final ServiceConnection connection = new ServiceConnection() {
        // 綁定服務(wù)成功
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder service) {
            // 接受到了遠(yuǎn)程的服務(wù)
            Log.d(TAG, "onServiceConnected!");
            aidlServer = IAidlServer.Stub.asInterface(service);
        }

        // 解綁服務(wù)
        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            Log.d(TAG, "onServiceDisconnected!");
            // 回收資源
            aidlServer = null;
        }
    };
}

先運(yùn)行服務(wù)端,再運(yùn)行客戶(hù)端,點(diǎn)擊客戶(hù)端的按鈕就可以實(shí)現(xiàn)AIDL的接口功能了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容