AIDL筆記

AIDL

1. 什麼是AIDL

AIDL(Android Interface Definition Language,即Android接口定義語言。)

IPC(Inter-Process Communication,進程間通信)。

在進程間通信不一定需要AIDL,因爲兩個進程間不能直接通信,需要Android系統底層間接實現通信,所以比較耗資源,能不用就不用。如下圖:
這裏寫圖片描述
進程間通訊可以分爲下面幾種:
AIDL
在IPC時,並且多個應用,多線程時纔用到。
Binder
只有IPC,多個應用,沒有多線程
Messager
只有IPC,沒有多線程

2. 創建AIDL

官方文檔上的例子:

// IRemoteService.aidl,//包名,文件必須放在指定的目錄
package com.example.android;

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

/** Example service interface */
interface IRemoteService {
    /** Request the process ID of this service, to do evil things with it. */
    int getPid();

    /** 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);
}

官方文檔上寫AIDL支持的數據類型包括:

  • 所有的基本數據類型;
  • String ,CharSequence
  • List,Map
    實際上基本數據類型的short類型不被支持,編譯都通不過。
    還有Parcelable(序列化)。
  • Parcelable(序列化)

那AIDL文件我們怎麼轉成java文件呢?在sdk\build-tools\23.0.2(版本)下有個aidl.exe文件,我們就是用這個來轉成java文件:

輸入命令:aidl IRemoteService.aidl

就會生成一個同名的java文件。

在eclipse中創建AIDL

新建一個Android項目後,直接在java文件中new一個aidl文件
這裏寫圖片描述

在eclipse中自動編譯生成java,而java就和R文件在一起:
這裏寫圖片描述
這樣就可以直接在Activity中提示出來了
這裏寫圖片描述

在Android studio中創建AIDL

而Android studio中和eclipse有點不同,是和java同級目錄創建
這裏寫圖片描述
這裏寫圖片描述
編譯後生成的java文件:這裏寫圖片描述

3. 下面用一個案例

客戶端傳兩個數字,調用服務端的計算方法求和
首先服務端的AIDL文件代碼:

package com.hou.aidl;

interface IMyAidlInterface {

    int add(int num1,int num2);
}

然後服務端需要遠程Service,代碼:

package com.hou.aidl;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;


public class IRemoteService extends Service {
    //當客戶端綁定服務時,會返回iBinder對象
    @Override
    public IBinder onBind(Intent intent) {
        return iBinder;
    }

    private IBinder iBinder = new IMyAidlInterface.Stub() {

        @Override
        public int add(int num1, int num2) throws RemoteException {
            Log.e("111", "收到了遠程傳過來的值" + num1 + "和" + num2);
            return num1 + num2;
        }
    };
}

note:需要在清單文件中註冊,並添加intent-filter

<service android:name=".IRemoteService">
      <intent-filter>
           <action android:name="com.hou.aidl.client" />
           <category android:name="android.intent.category.DEFAULT" />
      </intent-filter>
 </service>

客戶端:

package com.hou.aidlclient;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

import com.hou.aidl.IMyAidlInterface;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {


    private EditText et_num1;
    private EditText et_num2;
    private EditText et_sum;
    private Button btn_sum;
    private IMyAidlInterface iMyAidlInterface;
    private ServiceConnection conn = new ServiceConnection() {
        //服務綁定上的時候
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.e("111", "綁定服務成功==" + name);
            iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
        }

        //服務斷開的時候
        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.e("111", "服務斷開連接==" + name);
            iMyAidlInterface = null;
        }

    };

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

        initView();
        bindAidlService();
    }

    private void initView() {
        et_num1 = (EditText) findViewById(R.id.et_num1);
        et_num2 = (EditText) findViewById(R.id.et_num2);
        et_sum = (EditText) findViewById(R.id.et_sum);
        btn_sum = (Button) findViewById(R.id.btn_sum);
        btn_sum.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        int num1 = Integer.parseInt(et_num1.getText().toString());
        int num2 = Integer.parseInt(et_num2.getText().toString());
        try {
            int sum = iMyAidlInterface.add(num1, num2);
            et_sum.setText(sum + "");
        } catch (RemoteException e) {
            et_sum.setText("出錯了");
            e.printStackTrace();
        }
    }

    //綁定服務
    private void bindAidlService() {
        Intent intent = new Intent();
        //在Android5.0以後只能已顯示intent方式啓動 綁定服務
        intent.setComponent(new ComponentName("com.hou.aidl", "com.hou.aidl.IRemoteService"));
//        Intent intent = new Intent("com.hou.aidl.client");//隱式意圖方式
        bindService(intent, conn, Context.BIND_AUTO_CREATE);//Context.BIND_AUTO_CREATE自動創建
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(conn);
    }
}

現在就可以使用了,啓動服務端,打開客戶端就可以求和計算。

當然除過上邊提到的類型外,我們經常會傳遞自定義類型的數據,比如一個對象Person。

服務端:

創建一個Person對象,實現Parcelable序列化:

package com.hou.aidl;

import android.os.Parcel;
import android.os.Parcelable;

/**
 * Created by hp on 2016/3/9.
 */
public class Person implements Parcelable {

    public String name;
    public int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    protected Person(Parcel in) {
        //必須和writeToParcel中寫入的順序一致;
        name = in.readString();
        age = in.readInt();
    }

    public static final Creator<Person> CREATOR = new Creator<Person>() {
        @Override
        public Person createFromParcel(Parcel in) {
            return new Person(in);
        }

        @Override
        public Person[] newArray(int size) {
            return new Person[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(name);
        dest.writeInt(age);
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

創建Person.aidl

package com.hou.aidl;

parcelable  Person;
package com.hou.aidl;
//需要引入Person
import com.hou.aidl.Person;
interface IMyAidlInterface {

    List<Person> add(in Person person);
}

Service:

package com.hou.aidl;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;

import java.util.ArrayList;
import java.util.List;

public class IRemoteService extends Service {

    List<Person> persons;

    //當客戶端綁定服務時,會返回iBinder對象
    @Override
    public IBinder onBind(Intent intent) {
        persons = new ArrayList<>();
        return iBinder;
    }

    private IBinder iBinder = new IMyAidlInterface.Stub() {
        @Override
        public List<Person> add(Person person) throws RemoteException {
            persons.add(person);
            return persons;
        }
    };
}

客戶端:

把IMyAidlInterface.aidl和Person.aidl都複製到客戶端同名包下(aidl-com.hou.aidl)
把Person複製到客戶端同名包下(com.hou.aidl)

package com.hou.aidlclient;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

import com.hou.aidl.IMyAidlInterface;
import com.hou.aidl.Person;

import java.util.List;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private Button btn_sum;
    private IMyAidlInterface iMyAidlInterface;
    private ServiceConnection conn = new ServiceConnection() {
        //服務綁定上的時候
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.e("111", "綁定服務成功==" + name);
            iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
        }

        //服務斷開的時候
        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.e("111", "服務斷開連接==" + name);
            iMyAidlInterface = null;
        }

    };

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

        initView();
        bindAidlService();
    }

    private void initView() {
        btn_sum = (Button) findViewById(R.id.btn_sum);
        btn_sum.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        try {
            List<Person> persons = iMyAidlInterface.add(new Person("李四", 18));
            Person person = persons.get(0);
            et_sum.setText(person.toString());
        } catch (RemoteException e) {
            et_sum.setText("出錯了");
            e.printStackTrace();
        }
    }

    //綁定服務
    private void bindAidlService() {
        Intent intent = new Intent();
        //在Android5.0以後只能已顯示intent方式啓動 綁定服務
        intent.setComponent(new ComponentName("com.hou.aidl", "com.hou.aidl.IRemoteService"));
//        Intent intent = new Intent("com.hou.aidl.client");//隱式意圖方式
        bindService(intent, conn, Context.BIND_AUTO_CREATE);//Context.BIND_AUTO_CREATE自動創建
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(conn);
    }
}

AIDL原理圖

這裏寫圖片描述

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