欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android?創(chuàng)建AIDL文件使用教程

 更新時間:2022年07月29日 10:23:12   作者:??ByteSaid?  
這篇文章主要介紹了Android創(chuàng)建AIDL文件使用教程,AIDL是一種IDL語言,用于生成可以在Android設(shè)備上兩個進(jìn)程之間進(jìn)行進(jìn)程間通信的代碼

前言

AIDL(Android Interface Definition Language)是一種 IDL 語言,用于生成可以在 Android 設(shè)備上兩個進(jìn)程之間進(jìn)行進(jìn)程間通信(IPC)的代碼。 通過 AIDL,可以在一個進(jìn)程中獲取另一個進(jìn)程的數(shù)據(jù)和調(diào)用其暴露出來的方法,從而滿足進(jìn)程間通信的需求。通常,暴露方法給其他應(yīng)用進(jìn)行調(diào)用的應(yīng)用稱為服務(wù)端,調(diào)用其他應(yīng)用的方法的應(yīng)用稱為客戶端,客戶端通過綁定服務(wù)端的 Service 來進(jìn)行交互。

官方文檔中對 AIDL 有這樣一段介紹:

Using AIDL is necessary only if you allow clients from different applications to access your service for IPC and want to handle multithreading in your service. If you do not need to perform concurrent IPC across different applications, you should create your interface by implementing a Binder or, if you want to perform IPC, but do not need to handle multithreading, implement your interface using a Messenger. Regardless, be sure that you understand Bound Services before implementing an AIDL.

第一句很重要,“只有當(dāng)你允許來自不同的客戶端訪問你的服務(wù)并且需要處理多線程問題時你才必須使用AIDL”,其他情況下你都可以選擇其他方法,如使用 Messenger,也能跨進(jìn)程通信??梢?AIDL 是處理多線程、多客戶端并發(fā)訪問的,而 Messenger 是單線程處理。 下面介紹 AIDL 的使用方法。

1 創(chuàng)建 AIDL 文件

AIDL 文件可以分為兩類。一類用來聲明實現(xiàn)了 Parcelable 接口的數(shù)據(jù)類型,以供其他 AIDL 文件使用那些非默認(rèn)支持的數(shù)據(jù)類型。還有一類是用來定義接口方法,聲明要暴露哪些接口給客戶端調(diào)用。在 AIDL 文件中需要明確標(biāo)明引用到的數(shù)據(jù)類型所在的包名,即使兩個文件處在同個包名下。

默認(rèn)情況下,AIDL 支持下列數(shù)據(jù)類型:

  • 八種基本數(shù)據(jù)類型:byte、char、short、int、long、float、double、boolean
  • String,CharSequence
  • List類型。List承載的數(shù)據(jù)必須是AIDL支持的類型,或者是其它聲明的AIDL對象
  • Map類型。Map承載的數(shù)據(jù)必須是AIDL支持的類型,或者是其它聲明的AIDL對象

客戶端和服務(wù)端都需要創(chuàng)建,我們先在服務(wù)端中創(chuàng)建,然后復(fù)制到客戶端即可。在 Android Studio 中右鍵點擊新建一個 AIDL 文件,

如圖所示:

創(chuàng)建完成后,系統(tǒng)就會默認(rèn)創(chuàng)建一個 aidl 文件夾,文件夾下的目錄結(jié)構(gòu)即是工程的包名,AIDL 文件就在其中。

如圖所示:

文件中會有一個默認(rèn)方法,可以刪除掉,也可以新增其他方法。

2 實現(xiàn)接口

創(chuàng)建或修改過 AIDL 文件后需要 build 下工程,Android SDK 工具會生成以 .aidl 文件命名的 .java 接口文件(例如,IRemoteService.aidl 生成的文件名是 IRemoteService.java),在進(jìn)程間通信中真正起作用的就是該文件。生成的接口包含一個名為 Stub 的子類(例如,IRemoteService.Stub),該子類是其父接口的抽象實現(xiàn),并且會聲明 AIDL 文件中的所有方法。 如要實現(xiàn) AIDL 生成的接口,請實例化生成的 Binder 子類(例如,IRemoteService.Stub),并實現(xiàn)繼承自 AIDL 文件的方法。

以下是使用匿名內(nèi)部類實現(xiàn) IRemoteService 接口的示例:

private final IRemoteService.Stub binder = new IRemoteService.Stub() {
    public int getPid(){
        return Process.myPid();
    }
    public void basicTypes(int anInt, long aLong, boolean aBoolean,
        float aFloat, double aDouble, String aString) {
        // Does nothing
    }
};

現(xiàn)在,binder 是 Stub 類的一個實例(一個 Binder),其定義了服務(wù)端的 RPC 接口。

3 服務(wù)端公開接口

在為服務(wù)端實現(xiàn)接口后,需要向客戶端公開該接口,以便客戶端進(jìn)行綁定。創(chuàng)建 Service 并實現(xiàn) onBind(),從而返回生成的 Stub 的類實例。

以下是服務(wù)端的示例代碼:

public class RemoteService extends Service {
    private final String TAG = "RemoteService";
    @Override
    public void onCreate() {
        super.onCreate();
    }
    @Override
    public IBinder onBind(Intent intent) {
        // Return the interface
        Log.d(TAG, "onBind");
        return binder;
    }
    private final IRemoteService.Stub binder = new IRemoteService.Stub() {
        public int getPid() {
            return Process.myPid();
        }
        public void basicTypes(int anInt, long aLong, boolean aBoolean,
                               float aFloat, double aDouble, String aString) {
            Log.d(TAG, "basicTypes anInt:" + anInt + ";aLong:" + aLong + ";aBoolean:" + aBoolean + ";aFloat:" + aFloat + ";aDouble:" + aDouble + ";aString:" + aString);
        }
    };
}

我們還需要在 Manefest 文件中注冊我們創(chuàng)建的這個 Service,否則客戶端無法綁定服務(wù)。

        <service
            android:name=".RemoteService"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.example.aidl"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </service>

4 客戶端調(diào)用 IPC 方法

當(dāng)客戶端(如 Activity)調(diào)用 bindService() 以連接此服務(wù)時,客戶端的 onServiceConnected() 回調(diào)會接收服務(wù)端的 onBind() 方法所返回的 binder 實例。

客戶端還必須擁有接口類的訪問權(quán)限,因此如果客戶端和服務(wù)端在不同應(yīng)用內(nèi),則客戶端應(yīng)用的 src/ 目錄內(nèi)必須包含 .aidl 文件(該文件會生成 android.os.Binder 接口,進(jìn)而為客戶端提供 AIDL 方法的訪問權(quán)限)的副本。所以我們需要把服務(wù)端的 aidl 文件夾整個復(fù)制到客戶端的 java 文件夾同個層級下,不需要改動任何代碼。

當(dāng)客戶端在 onServiceConnected() 回調(diào)中收到 IBinder 時,它必須調(diào)用 IRemoteService.Stub.asInterface(service),以將返回的參數(shù)轉(zhuǎn)換成 IRemoteService 類型。例如:

IRemoteService iRemoteService;
private ServiceConnection mConnection = new ServiceConnection() {
    // Called when the connection with the service is established
    public void onServiceConnected(ComponentName className, IBinder service) {
        // Following the example above for an AIDL interface,
        // this gets an instance of the IRemoteInterface, which we can use to call on the service
        iRemoteService = IRemoteService.Stub.asInterface(service);
    }

    // Called when the connection with the service disconnects unexpectedly
    public void onServiceDisconnected(ComponentName className) {
        Log.e(TAG, "Service has unexpectedly disconnected");
        iRemoteService = null;
    }
};

獲得了 iRemoteService 對象,我們就可以調(diào)用 AIDL 中定義的方法了。如要斷開連接,可以調(diào)用unbindService() 方法。

以下是客戶端的示例代碼:

public class MainActivity extends AppCompatActivity {
    private final String TAG = "ClientActivity";
    private IRemoteService iRemoteService;
    private Button mBindServiceButton;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mBindServiceButton = findViewById(R.id.btn_bind_service);
        mBindServiceButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String text = mBindServiceButton.getText().toString();
                if ("Bind Service".equals(text)) {
                    Intent intent = new Intent();
                    intent.setAction("com.example.aidl");
                    intent.setPackage("com.example.aidl.server");
                    bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
                } else {
                    unbindService(mConnection);
                    mBindServiceButton.setText("Bind Service");
                }
            }
        });
    }
    ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.d(TAG, "onServiceDisconnected");
            iRemoteService = null;
        }
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.d(TAG, "onServiceConnected");
            iRemoteService = IRemoteService.Stub.asInterface(service);
            try {
                int pid = iRemoteService.getPid();
                int currentPid = Process.myPid();
                Log.d(TAG, "currentPID: " + currentPid + ", remotePID: " + pid);
                iRemoteService.basicTypes(12, 123, true, 123.4f, 123.45,
                        "服務(wù)端你好,我是客戶端");
            } catch (RemoteException e) {
                e.printStackTrace();
            }
            mBindServiceButton.setText("Unbind Service");
        }
    };
}

5 通過 IPC 傳遞對象

除了上面默認(rèn)支持的數(shù)據(jù)類型,AIDL 還可以傳遞對象,但是該類必須實現(xiàn) Parcelable 接口。而該類是兩個應(yīng)用間都需要使用到的,所以也需要在 AIDL 文件中聲明該類,為了避免出現(xiàn)類名重復(fù)導(dǎo)致無法創(chuàng)建 AIDL 文件的錯誤,這里需要先創(chuàng)建 AIDL 文件,之后再創(chuàng)建類。 先在服務(wù)端新建一個 AIDL 文件,比如 Rect.aidl,

示例如下:

// Rect.aidl
package com.example.aidl.server;

// Declare Rect so AIDL can find it and knows that it implements
// the parcelable protocol.
parcelable Rect;

然后就可以創(chuàng)建 Rect 類了,并使之實現(xiàn) Parcelable 接口。示例代碼如下:

public class Rect implements Parcelable {
    private int left;
    private int top;
    private int right;
    private int bottom;
    public Rect(int left, int top, int right, int bottom) {
        this.left = left;
        this.top = top;
        this.right = right;
        this.bottom = bottom;
    }
    public static final Parcelable.Creator<Rect> CREATOR = new Parcelable.Creator<Rect>() {
        public Rect createFromParcel(Parcel in) {
            return new Rect(in);
        }

        public Rect[] newArray(int size) {
            return new Rect[size];
        }
    };
    private Rect(Parcel in) {
        readFromParcel(in);
    }
    @Override
    public void writeToParcel(Parcel out, int flags) {
        out.writeInt(left);
        out.writeInt(top);
        out.writeInt(right);
        out.writeInt(bottom);
    }
    public void readFromParcel(Parcel in) {
        left = in.readInt();
        top = in.readInt();
        right = in.readInt();
        bottom = in.readInt();
    }
    @Override
    public int describeContents() {
        return 0;
    }
    @NonNull
    @Override
    public String toString() {
        return "Rect[left:" + left + ",top:" + top + ",right:" + right + ",bottom:" + bottom + "]";
    }
}

這樣我們就可以在之前創(chuàng)建的 IRemoteService.aidl 中新增一個方法來傳遞 Rect 對象了,示例代碼如下:

// IRemoteService.aidl
package com.example.aidl.server;
import com.example.aidl.server.Rect;
// Declare any non-default types here with import statements
interface IRemoteService {
    /**
     * 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 getPid();
    void addRectInOut(inout Rect rect);
}

注意這里需要明確導(dǎo)包:

import com.example.aidl.server.Rect;

然后將新增的 Rect.aidl 文件和 Rect.java 文件還有修改的 IRemoteService.aidl 文件同步到客戶端相同路徑下,

如圖所示:

build 下工程,就可以在客戶端調(diào)用到該 addRectInOut 方法了。

示例代碼如下:

    ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceDisconnected(ComponentName name) {
        }
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            iRemoteService = IRemoteService.Stub.asInterface(service);
            try {
                iRemoteService.addRectInOut(new Rect(1, 2, 3, 4));
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    };

到此這篇關(guān)于Android 創(chuàng)建AIDL文件使用教程的文章就介紹到這了,更多相關(guān)Android AIDL 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論