溫故而知新——AIDL

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

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

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

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

image.png

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

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


image.png

(三):將遠(yuǎn)程的aidl包拷貝到本地項(xiàng)目

后面還會(huì)介紹如何使用parcelable對(duì)象,其中實(shí)現(xiàn)parcelable對(duì)象的類,也需要寫一個(gè)aidl文件。


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

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


image.png

三:遠(yuǎn)程啟動(dòng)服務(wù)的注意事項(xiàng)

aidl一般是用在兩個(gè)進(jìn)程中,如果使用在兩個(gè)app中,那么要怎么從一個(gè)app啟動(dòng)另一個(gè)app的遠(yuǎn)程服務(wù)呢?在android 5.0之后,系統(tǒng)規(guī)定要使用顯示啟動(dòng)所有的service,否則就會(huì)拋出異常。因此就有下面兩種啟動(dòng)方式

(一)設(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)該是遠(yuǎn)程服務(wù)的applicationId, 然后是遠(yuǎn)程服務(wù)的全路徑名
intent.setComponent(new ComponentName("xiaguangcheng.com.local","xiaguangcheng.com.local.MyService"));

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


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

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

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

(二)使用parcelable接口的對(duì)象

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

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

public class BookManagerService extends Service {
    public static final String TAG="BMS";
    //讀寫分離,最終一致性,保障并發(fā)安全
    private CopyOnWriteArrayList<Book> mBookList=new CopyOnWriteArrayList<>();
    private AtomicBoolean mIsServiceDestoryed=new AtomicBoolean(false);
    //解決因?yàn)閍idl的序列化問題,導(dǎo)致傳遞過來的對(duì)象,已非客戶端的對(duì)象。這個(gè)類則解決了這個(gè)問題。
    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è)置一個(gè)死亡代理。即通過IBinder.linkToDeath(mDeathRecipient,0)來設(shè)置。其中這個(gè)死亡接收者有一個(gè)binderDied的回調(diào)。當(dāng)binder中斷,就需要在這個(gè)回調(diào)中,取消之前綁定死亡代理的那個(gè)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)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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