溫故而知新——AIDL

一:aidl與messenger的使用區(qū)別

  • aidl與messenger都是使用在進程間通信的方式兼蜈,底層都是Binder锭吨。不是進程間通信的可以直接使用Binder。
  • messenger底層使用的是aidl結(jié)構(gòu)。
  • messenger服務(wù)端串行執(zhí)行任務(wù)。
  • aidl可以實現(xiàn)并發(fā)操作好啰,但是要注意線程安全。aidl還可以調(diào)用遠程服務(wù)的方法儿奶,messenger則不可以框往。
  • aidl的同步主要是在aidl接口在service中的實現(xiàn)時添加。

二:一個簡單的aidl創(chuàng)建流程

(一):創(chuàng)建aidl文件

image.png

(二):創(chuàng)建遠程服務(wù)

注意aidl接口的方法闯捎,是需要線程安全的椰弊。


image.png

(三):將遠程的aidl包拷貝到本地項目

后面還會介紹如何使用parcelable對象,其中實現(xiàn)parcelable對象的類瓤鼻,也需要寫一個aidl文件秉版。


(四):綁定遠程服務(wù)

在調(diào)用aidl接口方法的時候,需要注意這個方法是耗時操作茬祷。


image.png

三:遠程啟動服務(wù)的注意事項

aidl一般是用在兩個進程中清焕,如果使用在兩個app中,那么要怎么從一個app啟動另一個app的遠程服務(wù)呢祭犯?在android 5.0之后秸妥,系統(tǒng)規(guī)定要使用顯示啟動所有的service,否則就會拋出異常盹憎。因此就有下面兩種啟動方式

(一)設(shè)置過濾器筛峭,google并不建議我們這么做

java.lang.IllegalArgumentException: Service Intent must be explicit: Intent { act=com.xia }

<service android:name=".MyService"
           >
            <intent-filter>
                <action android:name="com.xia"/>
            </intent-filter>
</service>

 intent.setAction("com.xia");
intent.setPackage("xiaguangcheng.com.local");

由于service設(shè)置了過濾器铐刘,那么exported就默認(rèn)為true了陪每。

(二)使用全類名打開service,主要要把允許其他app使用設(shè)置為true

java.lang.SecurityException: Not allowed to bind to service Intent { cmp=xiaguangcheng.com.local/.MyService }
 <service android:name=".MyService"
            android:exported="true">
  </service>
  //這里的pkg應(yīng)該是遠程服務(wù)的applicationId, 然后是遠程服務(wù)的全路徑名
intent.setComponent(new ComponentName("xiaguangcheng.com.local","xiaguangcheng.com.local.MyService"));

由于沒有設(shè)置過濾器镰吵,因此需要顯示指定exproted=true檩禾。


四:創(chuàng)建一個略復(fù)雜的aidl

(一)aidl支持的數(shù)據(jù)類型

  • 基本數(shù)據(jù)類型
  • String和CharSequence
  • ArrayList,元素必須被aidl支持
  • HashMap疤祭,元素必須被aidl支持
  • Parcelable盼产,所有實現(xiàn)了Parcelable接口的對象
  • aidl接口本身也能在aidl文件中使用

(二)使用parcelable接口的對象

  • 我們要在java包中創(chuàng)建一個Book.java文件實現(xiàn)parcelable接口
  • 我們還要在aidl包中創(chuàng)建一個同名的aidl文件Book.aidl,并在其中聲明parcelable Book;同時手動導(dǎo)入Book.java的包名勺馆。

(三)使用RemoteCallbackList刪除跨進程接口

public class BookManagerService extends Service {
    public static final String TAG="BMS";
    //讀寫分離戏售,最終一致性,保障并發(fā)安全
    private CopyOnWriteArrayList<Book> mBookList=new CopyOnWriteArrayList<>();
    private AtomicBoolean mIsServiceDestoryed=new AtomicBoolean(false);
    //解決因為aidl的序列化問題草穆,導(dǎo)致傳遞過來的對象灌灾,已非客戶端的對象。這個類則解決了這個問題悲柱。
    private RemoteCallbackList<IBookManagerNewBookArravied> mListenerList=
        new RemoteCallbackList<>();
    @Override
    public void onCreate() {
        super.onCreate();
        mBookList.add(new Book("西游記",111));
        mBookList.add(new Book("紅樓夢",222));
        new Thread(new ServiceWorker()).start();
    }

    private Binder mBinder=new IBookManager.Stub(){

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

        @Override
        public List<Book> getBookList() throws RemoteException {
            return mBookList;
        }

        @Override
        public void registerListener(IBookManagerNewBookArravied listener) throws RemoteException {
            mListenerList.register(listener);
        }

        @Override
        public void unRegisterListener(IBookManagerNewBookArravied Listener) throws RemoteException {
            mListenerList.unregister(Listener);
        }
    };
    public BookManagerService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        return mBinder;
    }

    private class ServiceWorker implements Runnable {
        @Override
        public void run() {
            while(!mIsServiceDestoryed.get()){
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                int bookId= mBookList.size()*111;
                Book newBook=new Book("bookName:"+bookId,bookId);
                try {
                    onNewBookArrrived(newBook);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private void onNewBookArrrived (Book newBook)throws RemoteException {
        mBookList.add(newBook);
        final int N=mListenerList.beginBroadcast();
        for(int i=0;i<N;i++){
            IBookManagerNewBookArravied iBookManagerNewBookArravied = mListenerList.getBroadcastItem(i);
            if(iBookManagerNewBookArravied!=null){
                iBookManagerNewBookArravied.onNewBookArrived(newBook);
            }
        }
        mListenerList.finishBroadcast();
    }

    @Override
    public void onDestroy() {
        mIsServiceDestoryed.set(true);
        super.onDestroy();
    }
}

五:如何判斷Binder連接是否中斷

在綁定服務(wù)完成之后锋喜,我們要給binder設(shè)置一個死亡代理。即通過IBinder.linkToDeath(mDeathRecipient,0)來設(shè)置。其中這個死亡接收者有一個binderDied的回調(diào)嘿般。當(dāng)binder中斷段标,就需要在這個回調(diào)中,取消之前綁定死亡代理的那個binder炉奴,重新綁定服務(wù)逼庞,綁定死亡代理。

    IM im;
    private IBinder.DeathRecipient mDeathRecipient=new IBinder.DeathRecipient(){
        @Override
        public void binderDied() {
            if(im==null){
                return;
            }
            im.asBinder().unlinkToDeath(mDeathRecipient,0);
            im=null;

           connect();

        }
    };
……
 public void connect(){
        Intent intent=new Intent("com.abc");
        intent.setPackage("com.xiaguangcheng.aidl");
        bindService(intent, new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                im=IM.Stub.asInterface(service);
                try {
                    service.linkToDeath(mDeathRecipient,0);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {

            }
        },BIND_AUTO_CREATE);
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末瞻赶,一起剝皮案震驚了整個濱河市往堡,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌共耍,老刑警劉巖虑灰,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異痹兜,居然都是意外死亡穆咐,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進店門字旭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來对湃,“玉大人,你說我怎么就攤上這事遗淳∨钠猓” “怎么了?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵屈暗,是天一觀的道長拆讯。 經(jīng)常有香客問我,道長养叛,這世上最難降的妖魔是什么种呐? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮弃甥,結(jié)果婚禮上爽室,老公的妹妹穿的比我還像新娘。我一直安慰自己淆攻,他們只是感情好阔墩,可當(dāng)我...
    茶點故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著瓶珊,像睡著了一般啸箫。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上艰毒,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天筐高,我揣著相機與錄音,去河邊找鬼。 笑死柑土,一個胖子當(dāng)著我的面吹牛蜀肘,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播稽屏,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼扮宠,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了狐榔?” 一聲冷哼從身側(cè)響起坛增,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎薄腻,沒想到半個月后收捣,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡庵楷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年罢艾,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片尽纽。...
    茶點故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡咐蚯,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出弄贿,到底是詐尸還是另有隱情春锋,我是刑警寧澤,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布差凹,位于F島的核電站期奔,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏直奋。R本人自食惡果不足惜能庆,卻給世界環(huán)境...
    茶點故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望脚线。 院中可真熱鬧,春花似錦弥搞、人聲如沸邮绿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽船逮。三九已至,卻和暖如春粤铭,著一層夾襖步出監(jiān)牢的瞬間挖胃,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留酱鸭,地道東北人吗垮。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像凹髓,于是被迫代替她去往敵國和親烁登。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,843評論 2 354

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