使用AIDL實(shí)現(xiàn)Android的跨進(jìn)程通信

歡迎Follow我的GitHub, 關(guān)注我的簡(jiǎn)書(shū). 其余參考Android目錄.

AIDL

本文的合集已經(jīng)編著成書(shū)舔示,高級(jí)Android開(kāi)發(fā)強(qiáng)化實(shí)戰(zhàn)驶社,歡迎各位讀友的建議和指導(dǎo)。在京東即可購(gòu)買(mǎi):https://item.jd.com/12385680.html

Android

AIDL(Android Interface Definition Language), 即Android接口定義語(yǔ)言. 在Android中, AIDL是跨進(jìn)程通信的主要實(shí)現(xiàn)方式. 我們同樣也可以使用AIDL, 實(shí)現(xiàn)自己的跨進(jìn)程方案. 本文介紹AIDL的使用方式.

服務(wù)端: 創(chuàng)建Service服務(wù)監(jiān)聽(tīng)客戶端的請(qǐng)求, 實(shí)現(xiàn)AIDL接口.

客戶端: 綁定服務(wù)端, 調(diào)用AIDL的方法.

AIDL接口: 跨進(jìn)程通信的接口, AIDL的包名需要與項(xiàng)目的包名相同, 默認(rèn)生成即可.

AIDL支持的數(shù)據(jù)類型: 基本類型, 字符串類型(String&CharSequence), List, Map, Parcelable, AIDL接口. 共六種.

流程: 客戶端注冊(cè)服務(wù)端, 服務(wù)端添加新書(shū), 客戶端接收, 并提供客戶端的查詢書(shū)數(shù)量的接口.

本文源碼的GitHub下載地址


AIDL

本文使用自定義的數(shù)據(jù)類型Book類, 實(shí)現(xiàn)Parcelable接口, 具體參考.

public class Book implements Parcelable {

    public int bookId;
    public String bookName;

    public Book(int bookId, String bookName) {
        this.bookId = bookId;
        this.bookName = bookName;
    }

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

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

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

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

    private Book(Parcel source) {
        bookId = source.readInt();
        bookName = source.readString();
    }

    @Override public String toString() {
        return "ID: " + bookId + ", BookName: " + bookName;
    }
}

AIDL使用自定義類, 需要聲明Parcelable類.

// IBook.aidl
package org.wangchenlong.wcl_aidl_demo;

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

parcelable Book;

添加AIDL的接口, 用于通知新書(shū)到達(dá).

// IOnNewBookArrivedListener.aidl
package org.wangchenlong.wcl_aidl_demo;

// Declare any non-default types here with import statements
import org.wangchenlong.wcl_aidl_demo.Book;

interface IOnNewBookArrivedListener {
    /**
     * 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);

    void onNewBookArrived(in Book newBook);
}

AIDL文件注釋較多, 都是自動(dòng)生成, 不影響閱讀.

核心AIDL類, 書(shū)籍管理器, 四個(gè)方法, 獲取圖書(shū)列表, 添加書(shū)籍, 注冊(cè)接口, 解注冊(cè)接口. 注意, 使用其他方法, 需要import導(dǎo)入相應(yīng)文件.

// IBookManager.aidl
package org.wangchenlong.wcl_aidl_demo;

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

import org.wangchenlong.wcl_aidl_demo.Book;
import org.wangchenlong.wcl_aidl_demo.IOnNewBookArrivedListener;

interface IBookManager {
    /**
     * 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);
    List<Book> getBookList(); // 返回書(shū)籍列表
    void addBook(in Book book); // 添加書(shū)籍
    void registerListener(IOnNewBookArrivedListener listener); // 注冊(cè)接口
    void unregisterListener(IOnNewBookArrivedListener listener); // 注冊(cè)接口
}

所有的參數(shù)都需要標(biāo)注參數(shù)方向, in表示輸入類型, out表示輸出類型, inout表示輸入輸出類型. out與inout的開(kāi)銷(xiāo)較大, 不能統(tǒng)一使用高級(jí)方向.


服務(wù)端

服務(wù)端通過(guò)Binder實(shí)現(xiàn)AIDL的IBookManager.Stub接口.

private Binder mBinder = new IBookManager.Stub() {
    @Override public List<Book> getBookList() throws RemoteException {
        SystemClock.sleep(5000); // 延遲加載
        return mBookList;
    }

    @Override public void addBook(Book book) throws RemoteException {
        mBookList.add(book);
    }

    @Override
    public void registerListener(IOnNewBookArrivedListener listener) throws RemoteException {
        mListenerList.register(listener);
        int num = mListenerList.beginBroadcast();
        mListenerList.finishBroadcast();
        Log.e(TAG, "添加完成, 注冊(cè)接口數(shù): " + num);
    }

    @Override
    public void unregisterListener(IOnNewBookArrivedListener listener) throws RemoteException {
        mListenerList.unregister(listener);
        int num = mListenerList.beginBroadcast();
        mListenerList.finishBroadcast();
        Log.e(TAG, "刪除完成, 注冊(cè)接口數(shù): " + num);
    }
};

服務(wù)啟動(dòng)時(shí), 添加兩本新書(shū), 并使用線程繼續(xù)添加.

@Override public void onCreate() {
    super.onCreate();
    mBookList.add(new Book(1, "Android"));
    mBookList.add(new Book(2, "iOS"));
    new Thread(new ServiceWorker()).start();
}

添加書(shū)籍, 并發(fā)送通知.

private class ServiceWorker implements Runnable {
    @Override public void run() {
        while (!mIsServiceDestroyed.get()) {
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            num++;
            if (num == 5) {
                mIsServiceDestroyed.set(true);
            }
            Message msg = new Message();
            mHandler.sendMessage(msg); // 向Handler發(fā)送消息,更新UI
        }
    }
}

private Handler mHandler = new Handler() {
    public void handleMessage(Message msg) {
        int bookId = 1 + mBookList.size();
        Book newBook = new Book(bookId, "新書(shū)#" + bookId);
        try {
            onNewBookArrived(newBook);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }
};

向注冊(cè)監(jiān)聽(tīng)的, 發(fā)送新書(shū)的添加通知.

private void onNewBookArrived(Book book) throws RemoteException {
    mBookList.add(book);
    Log.e(TAG, "發(fā)送通知的數(shù)量: " + mBookList.size());
    int num = mListenerList.beginBroadcast();
    for (int i = 0; i < num; ++i) {
        IOnNewBookArrivedListener listener = mListenerList.getBroadcastItem(i);
        Log.e(TAG, "發(fā)送通知: " + listener.toString());
        listener.onNewBookArrived(book);
    }
    mListenerList.finishBroadcast();
}

在AndroidManifest中, Service與Activity不在同一進(jìn)程.

<!--與主應(yīng)用不在同一進(jìn)程中-->
<service
    android:name=".BookManagerService"
    android:process=":remote"/>

客戶端

綁定服務(wù)和解綁服務(wù), 綁定服務(wù)的具體內(nèi)容, 都是在mConnection中實(shí)現(xiàn).

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mTextView = (TextView) findViewById(R.id.main_tv_book_list);
}

@Override protected void onDestroy() {
    if (mRemoteBookManager != null && mRemoteBookManager.asBinder().isBinderAlive()) {
        try {
            Log.e(TAG, "解除注冊(cè)");
            mRemoteBookManager.unregisterListener(mOnNewBookArrivedListener);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }
    unbindService(mConnection);
    super.onDestroy();
}

添加內(nèi)容, 注冊(cè)監(jiān)聽(tīng)接口.

private ServiceConnection mConnection = new ServiceConnection() {
    @Override public void onServiceConnected(ComponentName name, IBinder service) {
        IBookManager bookManager = IBookManager.Stub.asInterface(service);
        try {
            mRemoteBookManager = bookManager;
            Book newBook = new Book(3, "學(xué)姐的故事");
            bookManager.addBook(newBook);
            new BookListAsyncTask().execute();
            bookManager.registerListener(mOnNewBookArrivedListener);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    @Override public void onServiceDisconnected(ComponentName name) {
        mRemoteBookManager = null;
        Log.e(TAG, "綁定結(jié)束");
    }
};

當(dāng)調(diào)用監(jiān)聽(tīng)接口時(shí), 異步顯示圖書(shū)列表.

private IOnNewBookArrivedListener mOnNewBookArrivedListener = new IOnNewBookArrivedListener.Stub() {
    @Override public void onNewBookArrived(Book newBook) throws RemoteException {
        mHandler.obtainMessage(MESSAGE_NEW_BOOK_ARRIVED, newBook).sendToTarget();
    }
};

private Handler mHandler = new Handler() {
    @Override public void handleMessage(Message msg) {
        switch (msg.what) {
            case MESSAGE_NEW_BOOK_ARRIVED:
                Log.e(TAG, "收到的新書(shū): " + msg.obj);
                new BookListAsyncTask().execute();
                break;
            default:
                super.handleMessage(msg);
                break;
        }
    }
};

點(diǎn)擊綁定服務(wù)按鈕, 執(zhí)行綁定服務(wù). 點(diǎn)擊獲取圖書(shū)數(shù)量按鈕, 獲取當(dāng)前列表的數(shù)量.


效果

效果

Android跨進(jìn)程通信比較復(fù)雜, 但是意義重大, 目前常用的動(dòng)態(tài)加載框架都需要處理跨進(jìn)程通信等問(wèn)題, 熟練基本原理, 掌握使用方式.

OK, that's all! Enjoy it!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末筷转,一起剝皮案震驚了整個(gè)濱河市贺待,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌歉提,老刑警劉巖笛坦,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異苔巨,居然都是意外死亡版扩,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)侄泽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)礁芦,“玉大人,你說(shuō)我怎么就攤上這事∈量郏” “怎么了肖方?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)未状。 經(jīng)常有香客問(wèn)我俯画,道長(zhǎng),這世上最難降的妖魔是什么司草? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任艰垂,我火速辦了婚禮,結(jié)果婚禮上埋虹,老公的妹妹穿的比我還像新娘猜憎。我一直安慰自己,他們只是感情好搔课,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布胰柑。 她就那樣靜靜地躺著,像睡著了一般爬泥。 火紅的嫁衣襯著肌膚如雪柬讨。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,144評(píng)論 1 285
  • 那天袍啡,我揣著相機(jī)與錄音姐浮,去河邊找鬼。 笑死葬馋,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的肾扰。 我是一名探鬼主播畴嘶,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼集晚!你這毒婦竟也來(lái)了窗悯?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤偷拔,失蹤者是張志新(化名)和其女友劉穎蒋院,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體莲绰,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡欺旧,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蛤签。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片辞友。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出称龙,到底是詐尸還是另有隱情留拾,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布鲫尊,位于F島的核電站痴柔,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏疫向。R本人自食惡果不足惜咳蔚,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望鸿捧。 院中可真熱鬧屹篓,春花似錦、人聲如沸匙奴。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)泼菌。三九已至谍肤,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間哗伯,已是汗流浹背荒揣。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留焊刹,地道東北人系任。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像虐块,于是被迫代替她去往敵國(guó)和親俩滥。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

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

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,522評(píng)論 25 707
  • Android跨進(jìn)程通信IPC整體內(nèi)容如下 1贺奠、Android跨進(jìn)程通信IPC之1——Linux基礎(chǔ)2霜旧、Andro...
    隔壁老李頭閱讀 10,721評(píng)論 13 43
  • Jianwei's blog 首頁(yè) 分類 關(guān)于 歸檔 標(biāo)簽 巧用Android多進(jìn)程,微信儡率,微博等主流App都在用...
    justCode_閱讀 5,900評(píng)論 1 23
  • Android Interface Definition Language (AIDL) 注:本文翻譯自https...
    RxCode閱讀 1,543評(píng)論 0 2
  • 2017年3月3日 今天組會(huì)如預(yù)期挂据,很糟糕。然后我就挨批評(píng)了儿普。其實(shí)都不用批評(píng)崎逃,老師說(shuō)跟她的預(yù)期差很遠(yuǎn),這句話殺傷力...
    傅五歲閱讀 197評(píng)論 1 0