AIDL

AIDL學(xué)習(xí)筆記
AIDL是一門接口定義語(yǔ)言添吗,用于Android進(jìn)程間交互使用;
1瞬哼、為什么用aidl
2疆股、它相對(duì)其他IPC方案有什么優(yōu)劣
3、未來(lái)有更好的方案嗎

因?yàn)锳ndroid系統(tǒng)中每一個(gè)進(jìn)程都有獨(dú)立Dalvik VM實(shí)例倒槐,有自己的內(nèi)存區(qū)域旬痹,彼此互不干擾也無(wú)法互相直接通信。AIDL就是在需要通信的雙方定義一些公共的方法接口和需要傳遞的數(shù)據(jù)類型讨越。通信兩端具體實(shí)現(xiàn)接口的一方為服務(wù)端两残,調(diào)用接口的一方成為客戶端,客戶端調(diào)用服務(wù)端的相應(yīng)方法達(dá)到進(jìn)程間通信的目的把跨。具體的實(shí)現(xiàn)方式是服務(wù)的調(diào)用人弓。

語(yǔ)法特性:
文件類型:用AIDL書寫的文件的后綴是 .aidl,而不是 .java着逐。

數(shù)據(jù)類型:AIDL默認(rèn)支持一些數(shù)據(jù)類型崔赌,在使用這些數(shù)據(jù)類型的時(shí)候是不需要導(dǎo)包的,但是除了這些類型之外的數(shù)據(jù)類型耸别,在使用之前必須導(dǎo)包健芭,就算目標(biāo)文件與當(dāng)前正在編寫的 .aidl 文件在同一個(gè)包下——在 Java 中,這種情況是不需要導(dǎo)包的秀姐。比如慈迈,現(xiàn)在我們編寫了兩個(gè)文件,一個(gè)叫做 Book.java 省有,另一個(gè)叫做 BookManager.aidl痒留,它們都在 com.leo.aidldemo 包下 谴麦,現(xiàn)在我們需要在 .aidl 文件里使用 Book 對(duì)象,那么我們就必須在 .aidl 文件里面寫上 import com.leo.aidldemo.Book; 哪怕 .java 文件和 .aidl 文件就在一個(gè)包下伸头。
默認(rèn)支持的數(shù)據(jù)類型包括:
Java中的八種基本數(shù)據(jù)類型匾效,包括 byte,short恤磷,int面哼,long,float碗殷,double精绎,boolean,char锌妻。
String 類型代乃。
CharSequence類型。
List類型:只支持ArrayList仿粹,List中的所有元素必須是AIDL支持的類型之一搁吓,或者是一個(gè)其他AIDL生成的接口,或者是定義的parcelable(下文關(guān)于這個(gè)會(huì)有詳解)吭历,List可以使用泛型堕仔。
Map類型:只支持HashMap,Map中的所有元素必須是AIDL支持的類型之一晌区,或者是一個(gè)其他AIDL生成的接口摩骨,或者是定義的parcelable。Map是不支持泛型的朗若。

定向tag:這是一個(gè)極易被忽略的點(diǎn)——這里的“被忽略”指的不是大家都不知道恼五,而是很少人會(huì)正確的使用它。在我的理解里哭懈,定向 tag 是這樣的:AIDL中的定向 tag 表示了在跨進(jìn)程通信中數(shù)據(jù)的流向灾馒,其中 in 表示數(shù)據(jù)只能由客戶端流向服務(wù)端, out 表示數(shù)據(jù)只能由服務(wù)端流向客戶端遣总,而 inout 則表示數(shù)據(jù)可在服務(wù)端與客戶端之間雙向流通睬罗。其中,數(shù)據(jù)流向是針對(duì)在客戶端中的那個(gè)傳入方法的對(duì)象而言的旭斥。in 為定向 tag 的話表現(xiàn)為服務(wù)端將會(huì)接收到一個(gè)那個(gè)對(duì)象的完整數(shù)據(jù)容达,但是客戶端的那個(gè)對(duì)象不會(huì)因?yàn)榉?wù)端對(duì)傳參的修改而發(fā)生變動(dòng);out 的話表現(xiàn)為服務(wù)端將會(huì)接收到那個(gè)對(duì)象的的空對(duì)象琉预,但是在服務(wù)端對(duì)接收到的空對(duì)象有任何修改之后客戶端將會(huì)同步變動(dòng)董饰;inout 為定向 tag 的情況下,服務(wù)端將會(huì)接收到客戶端傳來(lái)對(duì)象的完整信息圆米,并且客戶端將會(huì)同步服務(wù)端對(duì)該對(duì)象的任何變動(dòng)卒暂。請(qǐng)不要濫用定向 tag ,而是要根據(jù)需要選取合適的——要是不管三七二十一娄帖,全都一上來(lái)就用 inout 也祠,等工程大了系統(tǒng)的開銷就會(huì)大很多——因?yàn)榕帕姓韰?shù)的開銷是很昂貴的。

實(shí)現(xiàn)原理:
由于不同的進(jìn)程有著不同的內(nèi)存區(qū)域近速,并且它們只能訪問自己的那一塊內(nèi)存區(qū)域诈嘿,所以我們不能像平時(shí)那樣,傳一個(gè)句柄過(guò)去就完事了——句柄指向的是一個(gè)內(nèi)存區(qū)域削葱,現(xiàn)在目標(biāo)進(jìn)程根本不能訪問源進(jìn)程的內(nèi)存奖亚,那把它傳過(guò)去又有什么用呢?所以我們必須將要傳輸?shù)臄?shù)據(jù)轉(zhuǎn)化為能夠在內(nèi)存之間流通的形式析砸。這個(gè)轉(zhuǎn)化的過(guò)程就叫做序列化與反序列化昔字。簡(jiǎn)單來(lái)說(shuō)是這樣的:比如現(xiàn)在我們要將一個(gè)對(duì)象的數(shù)據(jù)從客戶端傳到服務(wù)端去,我們就可以在客戶端對(duì)這個(gè)對(duì)象進(jìn)行序列化的操作首繁,將其中包含的數(shù)據(jù)轉(zhuǎn)化為序列化流作郭,然后將這個(gè)序列化流傳輸?shù)椒?wù)端的內(nèi)存中去,再在服務(wù)端對(duì)這個(gè)數(shù)據(jù)流進(jìn)行反序列化的操作弦疮,從而還原其中包含的數(shù)據(jù)——通過(guò)這種方式夹攒,我們就達(dá)到了在一個(gè)進(jìn)程中訪問另一個(gè)進(jìn)程的數(shù)據(jù)的目的。

而通常胁塞,在我們通過(guò)AIDL進(jìn)行跨進(jìn)程通信的時(shí)候咏尝,選擇的序列化方式是實(shí)現(xiàn) Parcelable 接口。

實(shí)現(xiàn)步驟:
1啸罢、通常我們需要n個(gè)定義parcelable對(duì)象和1個(gè)定義具體方法的aidl文件
實(shí)例如下:
// BookInterface.aidl
//這個(gè)文件的作用是引入了一個(gè)序列化對(duì)象 Book 供其他的AIDL文件使用
//注意:Book.aidl與Book.java的包名應(yīng)當(dāng)是一樣的
package leo.com.bookstoredemo;

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

parcelable Book;

// BookStoreInterface.aidl
package leo.com.bookstoredemo;

// Declare any non-default types here with import statements
//導(dǎo)入所需要使用的非默認(rèn)支持?jǐn)?shù)據(jù)類型的包
import leo.com.bookstoredemo.Book;

interface BookStoreInterface {
/**
* 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);
//所有的返回值前都不需要加任何東西编检,不管是什么數(shù)據(jù)類型
//傳參時(shí)除了Java基本類型以及String,CharSequence之外的類型
//都需要在前面加上定向tag伺糠,具體加什么量需而定
List<Book> getBooks();
void addBook(in Book book);
}

2蒙谓、注意點(diǎn):
2.1 默認(rèn)生成的模板類的對(duì)象只支持為 in 的定向 tag 。為什么呢训桶?因?yàn)槟J(rèn)生成的類里面只有 writeToParcel() 方法累驮,而如果要支持為 out 或者 inout 的定向 tag 的話,還需要實(shí)現(xiàn) readFromParcel() 方法舵揭。
2.2 如果AS無(wú)法識(shí)別Java或者aidl文件谤专,則應(yīng)該檢查aidl文件的包結(jié)構(gòu)是否和Java相同,如果還有問題午绳,應(yīng)該設(shè)置sourceset區(qū)分aidl和Java文件位置
sourceSets {
main {
java.srcDirs = ['src/main/java']
aidl.srcDirs = ['src/main/aidl']
}
}
此外置侍,服務(wù)端和客戶端的aidl文件目錄結(jié)構(gòu)必須完全相同,比如服務(wù)端的book.aidl在com.leo.bookstoredemo目錄下,客戶端也必須如此蜡坊「苁洌客戶端需要反序列化服務(wù)端中和AIDL相關(guān)的類,如果兩端文件路徑不一致秕衙,就不能反序列化成功蠢甲。
還有,如果需要在接口方法中使用非默認(rèn)支持的數(shù)據(jù)類型据忘,比如Book.java鹦牛,則定義parcelable對(duì)象的aidl文件也必須叫做Book.aidl否則編譯器是無(wú)法識(shí)別的。
2.3 AIDL方法是在服務(wù)端的Binder線程池中執(zhí)行的勇吊,如果有多個(gè)客戶端同時(shí)鏈接曼追,那么服務(wù)端要做好線程同步問題——對(duì)于List,可以使用CopyOnWriteArrayList汉规,問題來(lái)了礼殊,不是ArrayList為什么可行?因?yàn)槭紫绕淙匀皇荓ist的實(shí)現(xiàn)類鲫忍,關(guān)鍵在Binder中會(huì)根據(jù)List規(guī)則訪問數(shù)據(jù)并返回一個(gè)ArrayList給客戶端膏燕。
2.4服務(wù)端的方法可能通過(guò)很久才有相應(yīng),需要做好應(yīng)對(duì)ANR的措施
當(dāng)定義完aidl文件且這一步?jīng)]問題后悟民,通過(guò)clean或者build項(xiàng)目后坝辫,可以讓AS生成和aidl文件同名的Java文件,這就是具體的接口實(shí)現(xiàn)類

3射亏、現(xiàn)在貼上服務(wù)端的代碼

package leo.com.bookstoredemo;

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 java.util.ArrayList;
import java.util.List;

public class BookStoreService extends Service {

    private static final String TAG = "BookStoreService";

    private List<Book> mBooks = new ArrayList<>();

    private static final Object sObject = new Object();

    private BookStoreInterface.Stub mBookStoreManager = new BookStoreInterface.Stub(){
        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {

        }

        @Override
        public List<Book> getBooks() throws RemoteException {
            synchronized (sObject) {
                if(mBooks != null){
                    return mBooks;
                } else {
                    mBooks = new ArrayList<>();
                    return mBooks;
                }
            }
        }

        @Override
        public void addBook(Book book) throws RemoteException {
            synchronized (sObject) {
                if(mBooks == null) {
                    mBooks = new ArrayList<>();
                }
                if(book == null) {
                    book = new Book("A Book",10);
                    Log.e(TAG,"the Book added in is null !");
                }
                if(!mBooks.contains(book)){
                    book.setmBookPrice(book.getmBookPrice() * 2);
                    mBooks.add(book);
                    Log.i(TAG,"now adding the book and change its price to "+book.getmBookPrice());
                }
            }

        }
    };

    @Override
    public void onCreate() {
        super.onCreate();
        Book originalBook = new Book("tap dancing to work",30);
        mBooks.add(originalBook);
        Log.i(TAG,"original book list is: "+originalBook.toString());
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.i(TAG,"Bookstore's manager has been connected: "+mBookStoreManager.toString());
        return mBookStoreManager;
    }
}
4近忙、客戶端的代碼
package leo.com.bookstorecustomer;

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.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;

import java.util.List;

import leo.com.bookstoredemo.Book;
import leo.com.bookstoredemo.BookStoreInterface;

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";

    private BookStoreInterface mBookStoreInterface = null;

    private boolean mHasBound = false;

    private List<Book> mBooks = null;

    private Button mAddBookButton = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mAddBookButton = findViewById(R.id.add_book);
        mAddBookButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(mHasBound && mBookStoreInterface != null) {
                    Book book = new Book("fucking android",50);
                    try {
                        mBookStoreInterface.addBook(book);
                        Log.i(TAG,"the book has been added to list "+book.toString());
                    }catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        });
    }

    @Override
    protected void onStart() {
        super.onStart();
        attemptToBindService();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(mConnectionService);
        mBookStoreInterface = null;
        mHasBound = false;
    }

    private void attemptToBindService() {
        Intent intent = new Intent("com.leo.bookstore.manager");
        intent.setPackage("leo.com.bookstoredemo");
        bindService(intent,mConnectionService, Context.BIND_AUTO_CREATE);
    }

    private ServiceConnection mConnectionService = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            Log.i(TAG,"Service connected !");
            mBookStoreInterface = BookStoreInterface.Stub.asInterface(iBinder);
            mHasBound = true;
            if(mBookStoreInterface != null) {
                try {
                    mBooks = mBookStoreInterface.getBooks();
                    Log.i(TAG,"customer has connected bookstore and get a book list: "+mBooks.toString());
                }catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            mBookStoreInterface = null;
            mHasBound = false;
            Log.i(TAG,"Service disconnected");
        }
    };
}
通過(guò)log可以看到整個(gè)通信的流程和定向tag的作用
07-29 15:21:21.245  3079  3079 I BookStoreService: original book list is: Book{mBookName='tap dancing to work', mBookPrice=30}
07-29 15:21:21.245  3079  3079 I BookStoreService: Bookstore's manager has been connected: leo.com.bookstoredemo.BookStoreService$1@986cd9a
07-29 15:21:21.256  2838  2838 I MainActivity: Service connected !
07-29 15:21:21.257  2838  2838 I MainActivity: customer has connected bookstore and get a book list: [Book{mBookName='tap dancing to work', mBookPrice=30}]


07-29 15:22:14.991  3079  3092 I BookStoreService: now adding the book and change its price to 100
07-29 15:22:14.991  2838  2838 I MainActivity: the book has been added to list Book{mBookName='fucking android', mBookPrice=50}

完整demo地址  https://github.com/LeeFranz/AndroidIPC

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市智润,隨后出現(xiàn)的幾起案子及舍,更是在濱河造成了極大的恐慌,老刑警劉巖窟绷,帶你破解...
    沈念sama閱讀 217,734評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件锯玛,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡兼蜈,警方通過(guò)查閱死者的電腦和手機(jī)攘残,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)为狸,“玉大人歼郭,你說(shuō)我怎么就攤上這事》簦” “怎么了病曾?”我有些...
    開封第一講書人閱讀 164,133評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵牍蜂,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我泰涂,道長(zhǎng)鲫竞,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,532評(píng)論 1 293
  • 正文 為了忘掉前任负敏,我火速辦了婚禮贡茅,結(jié)果婚禮上秘蛇,老公的妹妹穿的比我還像新娘其做。我一直安慰自己,他們只是感情好赁还,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評(píng)論 6 392
  • 文/花漫 我一把揭開白布妖泄。 她就那樣靜靜地躺著,像睡著了一般艘策。 火紅的嫁衣襯著肌膚如雪蹈胡。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,462評(píng)論 1 302
  • 那天朋蔫,我揣著相機(jī)與錄音罚渐,去河邊找鬼。 笑死驯妄,一個(gè)胖子當(dāng)著我的面吹牛荷并,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播青扔,決...
    沈念sama閱讀 40,262評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼源织,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了微猖?” 一聲冷哼從身側(cè)響起谈息,我...
    開封第一講書人閱讀 39,153評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎凛剥,沒想到半個(gè)月后侠仇,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,587評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡犁珠,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評(píng)論 3 336
  • 正文 我和宋清朗相戀三年逻炊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片盲憎。...
    茶點(diǎn)故事閱讀 39,919評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡嗅骄,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出饼疙,到底是詐尸還是另有隱情溺森,我是刑警寧澤慕爬,帶...
    沈念sama閱讀 35,635評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站屏积,受9級(jí)特大地震影響医窿,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜炊林,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評(píng)論 3 329
  • 文/蒙蒙 一姥卢、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧渣聚,春花似錦独榴、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至隘道,卻和暖如春症歇,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背谭梗。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工忘晤, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人激捏。 一個(gè)月前我還...
    沈念sama閱讀 48,048評(píng)論 3 370
  • 正文 我出身青樓设塔,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親缩幸。 傳聞我的和親對(duì)象是個(gè)殘疾皇子壹置,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容