1. 程式人生 > 其它 >Android 跨程序通訊之AIDL

Android 跨程序通訊之AIDL

前言

  在Android跨程序通訊的方式有很多比如廣播,ContentProvider,AIDL等等,它們各自有各自的使用範圍。而且AIDL更像是Java的ServerSocket通訊機制, 需要一個常駐的服務端與呼叫它的客戶端。AIDL現在的缺點可能也是需要一個服務配合使用。因為目前Android端Server的使用要求越來越多(前臺化),使用場景也越來越少(WorkManager替代),所有

簡單實現Demo

服務端

建立AIDL

建立

完成後,在這個預設檔案裡會有一些預設方法,它告訴你了AIDL可以使用那些型別資料

編輯AIDL檔案

編輯完成後,ReBuild 重新編譯下整個專案,Android stuido會自動在debug裡生成一份對應的aidl的java介面類

package com.zh.aidl;

interface IDemoService {
    void setNum(int num);
    int getNum();
}

自動生成的java介面

建立服務,將服務繫結AIDL

註冊清單

        <!--    android:enabled="true" 與 android:exported="true"  是必要屬性 -->

        <!--    android:enabled 定義服務能否被系統例項化的標籤,true表示可以例項化,false不能例項化,預設為true。標籤也有enabled標籤,這個標籤適用於application下所有元件。
                只有當和下enabled標籤的屬性都為true的時候,才可以將廣播接受者啟動(enabled),否則廣播接受者不能開啟(disabled),不能被例項化。  
--> <!-- android:exported 定義服務能否被外部應用的元件呼叫或者互動,true表示可以,false表示不能。 如果設定為false,服務只能接收本應用的元件或者是具有相同使用者ID的應用所發出的所開啟或繫結。 --> <service android:name=".DemoService" android:enabled="true" android:exported="true"> <
intent-filter> <action android:name="DemoService" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </service> </application>

服務

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.os.Build;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;

public class DemoService extends Service {
    private static final String CHANNEL_ID = "DemoService";
    private int mNum = 0;

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        //繫結AIDL
        return iBinder;
    }

    /**
     * 例項化AIDL
     */
    private IBinder iBinder = new IDemoService.Stub() {
        @Override
        public void setNum(int num) throws RemoteException {
            mNum = num;
            Log.e("zh", "伺服器端接收資料: Num = " + num);

        }

        @Override
        public int getNum() throws RemoteException {
            return mNum;
        }
    };

    @Override
    public void onCreate() {
        super.onCreate();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            frontDeskService();
        }
    }

    /**
     * 前臺服務
     */
    @RequiresApi(api = Build.VERSION_CODES.O)
    private void frontDeskService() {
        NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "主服務", NotificationManager.IMPORTANCE_HIGH);
        channel.enableLights(true);//設定提示燈
        channel.setLightColor(Color.RED);//設定提示燈顏色
        channel.setShowBadge(true);//顯示logo
        channel.setDescription("zh");//設定描述
        channel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC); //設定鎖屏可見 VISIBILITY_PUBLIC=可見
        manager.createNotificationChannel(channel);

        Notification notification = new Notification.Builder(this)
                .setChannelId(CHANNEL_ID)
                .setContentTitle("主服務")//標題
                .setContentText("執行中...")//內容
                .setWhen(System.currentTimeMillis())
                .setSmallIcon(R.mipmap.ic_launcher)//小圖示一定需要設定,否則會報錯(如果不設定它啟動服務前臺化不會報錯,但是你會發現這個通知不會啟動),如果是普通通知,不設定必然報錯
                .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
                .build();
        startForeground(1, notification);
    }
}

啟動服務

    private fun startService() {
        val intent = Intent(this, DemoService::class.java)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            startForegroundService(intent)
        } else{
            startService(intent)
        }
    }

客戶端

將服務端的AIDL檔案複製到客戶端裡,注意包名路徑要一致

 繫結服務,接收資料,傳送資料

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(mBinding.root)

        mBinding.connectService.setOnClickListener {
            //繫結服務
            val intent = Intent().apply {
                setPackage("com.zh.aidl")
                setAction("DemoService")
            }
            bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE)
        }

        mBinding.sendValue.setOnClickListener {
            //傳送資料
            mIDemoService?.num = mBinding.editTextNumber.text.toString().toInt()
        }
        mBinding.getValue.setOnClickListener {
            //接收資料
            Log.e("zh", "客戶端接收: num = " + mIDemoService?.num)
        }
    }

End