一塊兒簡單寫一下AIDL,入個門

前話

最近接觸了Android開發的一個新知識,AIDL(¬_¬由於到如今都沒用過)
所以不斷谷歌找資料找Demo,本身嘗試寫一下。
由於用AndroidStudio做爲開發環境,期間遇到過許多問題,所以寫下來看成筆記,也給新接觸這個知識點的同窗們一個小指引。html

這裏推薦兩篇文章:java

Android:學習AIDL,這一篇文章就夠了(上)android

Android:學習AIDL,這一篇文章就夠了(下)markdown


什麼是AIDL

什麼是AIDL?這個谷歌一下有不少,我就摘抄一段 ↓多線程

對於AIDL有一些人的淺顯概念就是,AIDL能夠跨進程訪問其餘應用程序,和其餘應用程序通信。併發

那我告訴你,不少技術均可以訪問。app

如廣播(應用A在AndroidManifest.xml中註冊指定Action的廣播)應用B發送指定Action的廣播,A就能收到信息,這樣也能當作不一樣應用之間完成了通信(可是這種通信是單向的);
還如ContentProvider,經過URI接口暴露數據給其餘應用訪問;less

可是這種都算不上是應用之間的通信。可能最讓人迷惑的是Android推出來了Messager,它就是完成應用之間的通信的。ide

那麼爲何還要有AIDL呢,官方文檔介紹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.

第一句最重要,「只有當你容許來自不一樣的客戶端訪問你的服務而且須要處理多線程問題時你才必須使用AIDL」,其餘狀況下你均可以選擇其餘方法,如使用Messager,也能跨進程通信。

可見AIDL是處理多線程、多客戶端併發訪問的。

而Messager是單線程處理。仍是官方文檔說的明白,一句話就能夠理解爲何要有AIDL。

看到這裏你們應該也簡單知道什麼是AIDL了,下面咱們簡單動手寫一下AIDL,能夠加深理解。


一塊兒寫AIDL

這次使用AIDL,咱們就用來在兩個不一樣進程間傳輸複雜數據吧。

首先咱們定義一下需求,咱們想實現這樣的功能,就是一個服務端啓動一個Service,這個Service用來接收客戶端傳來的數據,並將該數據打印出來。

客戶端 –> 客戶端傳遞數據(例如User類對象) –> 服務端 –>服務端打印接收到的數據

結合這樣的功能需求,咱們須要建立兩個APP。

  • 一個APP做爲服務端用來啓動Service接收並打印數據
  • 一個APP做爲客戶端用來綁定服務端的Service並傳遞數據給該Service

服務端

最終項目結構

01


源碼

User.aidl 和 User.java

由於要傳遞複雜數據,這裏用User做爲例子,所以咱們要定義User的AIDL文件。

由於開發環境是AndroidStudio,因此咱們要先在aidl文件夾內建立 User.aidl

User.aidl

package me.pwcong.aidlservice.model;

parcelable User;

而後咱們再在java文件夾內建立User.java。
由於User做爲複雜數據,在不一樣進程之間傳遞須要序列化,所以它須要繼承Parcelable。
這裏源碼省略get、set和toString方法。

User.java

package me.pwcong.aidlservice.model;

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

public class User implements Parcelable {

    String name;
    int age;
    String gender;

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

    public void readFromParcel(Parcel dest){
        this.name=dest.readString();
        this.age=dest.readInt();
        this.gender=dest.readString();
    }

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

    public User() {
    }

    protected User(Parcel in) {
        this.name = in.readString();
        this.age = in.readInt();
        this.gender = in.readString();
    }

    public static final Parcelable.Creator<User> CREATOR = new Parcelable.Creator<User>() {
        @Override
        public User createFromParcel(Parcel source) {
            return new User(source);
        }

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

特別注意,User.aidl 和 User.java 和包名和路徑必需要同樣
例如上面User.aidl和User.java的包路徑均爲 package me.pwcong.aidlservice.model;


MainInterface.aidl

接着咱們定義一個接口AIDL文件,用做不一樣進程間傳遞數據。

MainInterface.aidl

package me.pwcong.aidlservice;

//引用其餘類文件是否在同一包內都須要import
import me.pwcong.aidlservice.model.User;

interface MainInterface {

    //注意這裏的前綴in,表示數據流只能由客戶端傳到服務端    
    void introduce(in User user);
}

到這裏咱們就寫好了服務端的AIDL,咱們將該項目make一下,若是沒有報錯,則說明AIDL成功的編譯導出了相關的java類文件,在generate文件夾內能夠找到。


MainActivity和MainService

MainService.java

package me.pwcong.aidlservice.component.service;

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

import me.pwcong.aidlservice.MainInterface;
import me.pwcong.aidlservice.model.User;

public class MainService extends Service {

    private final String TAG=getClass().getSimpleName();

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mainInterface;
    }

    private final MainInterface.Stub mainInterface=new MainInterface.Stub() {
        @Override
        public void introduce(User user) throws RemoteException {
            Log.i(TAG, "introduce: "+ user.toString());
        }
    };


}

MainActivity.java

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

import me.pwcong.aidlservice.R;

public class MainActivity extends AppCompatActivity {

    private final String TAG=getClass().getSimpleName();

    ServiceConnection serviceConnection=new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.i(TAG, "onServiceConnected: OK");
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.i(TAG, "onServiceDisconnected: OK");
        }
    };


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

        Intent intent=new Intent();
        intent.setAction("me.pwcong.aidlservice.aidl");
        startService(intent);

        bindService(intent,serviceConnection,BIND_AUTO_CREATE);

    }
}

最後在AndroidManifest.xml內進行Service的配置

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="me.pwcong.aidlservice">

    <application  android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme">
        <activity android:name=".component.activity.MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service android:name=".component.service.MainService">

            <intent-filter>

                <action android:name="me.pwcong.aidlservice.aidl"/>
                <category android:name="android.intent.category.DEFAULT"/>

            </intent-filter>

        </service>


    </application>

</manifest>

啓動服務端

咱們點擊運行,若logcat中輸出以下這句說明服務端Service啓動成功

09-13 02:44:36.888 1413-1413/? I/MainActivity: onServiceConnected: OK

客戶端

最終文件結構

02


源碼

User.java,User.aidl 和 MainInterface.aidl

由於客戶端須要傳遞數據給服務端,所以它的AIDL文件必須和服務端的同樣,因此咱們將服務端的User.java,User.aidl 和 MainInterface.aidl 拷貝至相應目錄。

特別注意,這三個文件的包名路徑務必和服務端一致,如上圖最終文件結構所示

接着咱們再make一下項目,若是沒有報錯,咱們就能夠進行下一步了


MainActivity.java 和 AndroidManifest.xml

MainActivity.java

package me.pwcong.aidlclient;

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

import me.pwcong.aidlservice.MainInterface;
import me.pwcong.aidlservice.model.User;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private final String TAG=getClass().getSimpleName();

    Button button;

    MainInterface mainInterface;

    ServiceConnection serviceConnection=new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //將綁定的service轉成所定義的AIDL接口類
            mainInterface= MainInterface.Stub.asInterface(service);

            Log.i(TAG, "onServiceConnected: "+name);
            Log.i(TAG, "onServiceConnected: OK");
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.i(TAG, "onServiceDisconnected: "+name);
            Log.i(TAG, "onServiceDisconnected: OK");
        }
    };

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

        Intent intent=new Intent();

        //特別注意這裏設置了服務端APP的包名
        intent.setPackage("me.pwcong.aidlservice");
        //這裏設置action爲服務端APP對Service所定義的action值
        intent.setAction("me.pwcong.aidlservice.aidl");

        bindService(intent,serviceConnection,BIND_AUTO_CREATE);

        button= (Button) findViewById(R.id.btn);
        button.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {

        if(mainInterface!=null){

            User user=new User();
            user.setName("Pwcong");
            user.setAge(20);
            user.setGender("Man");

            try {
                mainInterface.introduce(user);
            } catch (RemoteException e) {
                e.printStackTrace();
            }

        }

    }
}

這個Activity裏面簡單實現了綁定服務端的Service,和經過點擊按鈕給服務端Service發送User類對象數據。

AndroidMainifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="me.pwcong.aidlclient">

    <application  android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

啓動客戶端

咱們運行客戶端,若輸出以下說明客戶端綁定服務端Service成功:

09-13 03:05:17.552 20379-20379/me.pwcong.aidlclient I/MainActivity: onServiceConnected: OK

接着咱們點擊按鈕,若輸出以下說明AIDL傳輸數據成功:

09-13 03:08:01.520 1413-1426/me.pwcong.aidlservice I/MainService: introduce: User{name='Pwcong', age=20, gender='Man'}

結束

到這裏咱們簡單的AIDL入門就寫完了。

若是這次入門項目書寫事後仍懵懂的話我仍是推薦你們認真閱讀前面所推薦的兩篇入門文章吧。

畢竟我也是剛入門哈。

相關文章
相關標籤/搜索