天天看點

Android AIDL 學習使用

來源:https://developer.android.com/guide/components/aidl

        最近沒事看了下Google對于AIDL的說明,自己了解了一下,做一下筆記,筆記中的代碼都是自己敲出來的,之前自己看别人的文章服務端和用戶端都在一個應用裡,雖然指定了UID但是總感覺差了點,于是就自己試了一下服務端和用戶端在不同的應用中的寫法

一   google官方說明

The Android Interface Definition Language (AIDL) is similar to other IDLs you might have worked with. It allows you to define the programming interface that both the client and service agree upon in order to communicate with each other using interprocess communication (IPC). On Android, one process cannot normally access the memory of another process. So to talk, they need to decompose their objects into primitives that the operating system can understand, and marshall the objects across that boundary for you. The code to do that marshalling is tedious to write, so Android handles it for you with AIDL.

Note: 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.

Before you begin designing your AIDL interface, be aware that calls to an AIDL interface are direct function calls. You should not make assumptions about the thread in which the call occurs. What happens is different depending on whether the call is from a thread in the local process or a remote process. Specifically:

  • Calls made from the local process are executed in the same thread that is making the call. If this is your main UI thread, that thread continues to execute in the AIDL interface. If it is another thread, that is the one that executes your code in the service. Thus, if only local threads are accessing the service, you can completely control which threads are executing in it (but if that is the case, then you shouldn't be using AIDL at all, but should instead create the interface by implementing a Binder).
  • Calls from a remote process are dispatched from a thread pool the platform maintains inside of your own process. You must be prepared for incoming calls from unknown threads, with multiple calls happening at the same time. In other words, an implementation of an AIDL interface must be completely thread-safe.
  • The 

    oneway

     keyword modifies the behavior of remote calls. When used, a remote call does not block; it simply sends the transaction data and immediately returns. The implementation of the interface eventually receives this as a regular call from the 

    Binder

     thread pool as a normal remote call. If 

    oneway

     is used with a local call, there is no impact and the call is still synchronous.

看了google對aidl的定義,因為是英文的,看的有點懵懵懂懂的,如果有英文比較好的大佬能幫忙翻譯了解一下,然後用通俗易懂的方式留下言就萬分感謝了

我自己了解了一下,大概就是有多個應用通路同一個服務而且想要在服務端做多線程處理的時候google才建議使用aidl

二  使用aidl

     1 建立aidl檔案IMyAidlInterface.aidl

// IMyAidlInterface.aidl
package com.example.cslrcj.myaidltest1;
import com.example.cslrcj.myaidltest1.Persion;
// Declare any non-default types here with import statements

interface IMyAidlInterface {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void add(in Persion persion);
    List<Persion> getPersion();
    int getPid();
}           

      由于aidl本身支援資料類型如下:

  • Java 程式設計語言中的所有原語類型(如 

    int

    long

    char

    boolean

     等等)
  • String

  • CharSequence

  • List

    List

     中的所有元素都必須是以上清單中支援的資料類型、其他 AIDL 生成的接口或您聲明的可打包類型。 可選擇将 

    List

     用作“通用”類(例如,

    List<String>

    )。另一端實際接收的具體類始終是 

    ArrayList

    ,但生成的方法使用的是 

    List

     接口。
  • Map

    Map

     中的所有元素都必須是以上清單中支援的資料類型、其他 AIDL 生成的接口或您聲明的可打包類型。 不支援通用 Map(如 

    Map<String,Integer>

     形式的 Map)。 另一端實際接收的具體類始終是 

    HashMap

    ,但生成的方法使用的是 

    Map

     接口。

    但是在實際工作中我們可能需要傳一些自己定義的類,如果這樣的話我們必須将我們自己定義的類序列化,不然是不能傳的,我這裡面也是加了一個自己定義的類Persion,貼下一我的代碼:

    在IMyAidlInterface.aidl檔案的同級目錄下建立Persion.aidl

// IPersion.aidl
package com.example.cslrcj.myaidltest1;

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

parcelable Persion;
           

aidl檔案是有些編寫規則的:

1 除了aidl本身支援的那些資料類型,其他我們自己定義的如果有用到必須用import導入才可以

2  方法可帶零個或多個參數,傳回值或空值

3  所有非原語參數都需要訓示資料走向的方向标記。可以是 in、out 或 inout(見以下示例)。 ----預設是in 這個最好标記正确,比較對記憶體開銷比較大

2  服務端編寫

建立一個service,實作onbind方法傳回自己的aidl,代碼如下:

public class MyIntentService extends IntentService {
    @Override
    public IBinder onBind(Intent intent) {
        return myBinder;
        //return super.onBind(intent);
    }

    public IBinder myBinder = new IMyAidlInterface.Stub() {
        @Override
        public void add(Persion persion) throws RemoteException {

        }

        @Override
        public List<Persion> getPersion() throws RemoteException {
            return null;
        }

        @Override
        public int getPid() throws RemoteException {
            return Process.myUid();
        }
    };           

當用戶端(如 Activity)調用 bindService() 以連接配接此服務時,用戶端的 onServiceConnected() 回調會接收服務的 onBind() 方法傳回的 mBinder 執行個體。

3 用戶端使用

由于是在不同的應用中,是以我們需要将aidl相關的配置都複制到用戶端,并且包名都應該一樣才可以使用,用戶端代碼:

public class MainActivity extends AppCompatActivity {
    IMyAidlInterface myAidlInterface;
    List<Persion> mPersionList = new ArrayList<>();
    private TextView tv_show_persion;
    int serviceUid;
    ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            myAidlInterface = IMyAidlInterface.Stub.asInterface(service);
            try {

                myAidlInterface.add(new Persion(12, "lisi"));
                mPersionList = myAidlInterface.getPersion();
                serviceUid = myAidlInterface.getPid();

            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv_show_persion = findViewById(R.id.tv_show_persion);
        Intent mIntent = new Intent("com.example.cslrcj.myaidltest1.MyIntentService");
        mIntent.setPackage("com.example.cslrcj.myaidltest1");
        bindService(mIntent, serviceConnection, Service.BIND_AUTO_CREATE);
    }
           

這樣差不多就行了,附帶一下項目的結構圖

Android AIDL 學習使用
Android AIDL 學習使用