AIDL使用解析

之前面試的時(shí)候被問到這個(gè)問題改橘,然而當(dāng)時(shí)只有一個(gè)大致的印象盅弛,隨GG畔况,于是我就重新整理的一下。這里大力推薦《Android開發(fā)藝術(shù)探索》這本書憋沿,寫的太好了!

1.AIDL

AIDL(Android Interface Define Language) 是IPC進(jìn)程間通信方式的一種.用于生成可以在Android設(shè)備上兩個(gè)進(jìn)程之間進(jìn)行進(jìn)程間通信(interprocess communication, IPC)的代碼.

2.AIDL和Messenger的區(qū)別:

  1. Messenger不適用大量并發(fā)的請求:Messenger以串行的方式來處理客戶端發(fā)來的消息沪猴,如果大量的消息同時(shí)發(fā)送到服務(wù)端辐啄,服務(wù)端仍然只能一個(gè)個(gè)的去處理。
  2. Messenger主要是為了傳遞消息:對于需要跨進(jìn)程調(diào)用服務(wù)端的方法运嗜,這種情景不適用Messenger壶辜。
  3. Messenger的底層實(shí)現(xiàn)是AIDL,系統(tǒng)為我們做了封裝從而方便上層的調(diào)用担租。
  4. AIDL適用于大量并發(fā)的請求砸民,以及涉及到服務(wù)端端方法調(diào)用的情況

3.使用AIDL的步驟:

下面一個(gè)簡單的例子來說明AIDL的使用:假設(shè)一個(gè)情景我們需要計(jì)算a+b,我們需要在客戶端傳遞兩個(gè)參數(shù)a和b,然后將參數(shù)傳遞給服務(wù)端(另一個(gè)進(jìn)程)來進(jìn)行計(jì)算岭参,計(jì)算結(jié)果傳遞給客戶端反惕。

目錄結(jié)構(gòu)

** 1. 新建一個(gè)項(xiàng)目作為服務(wù)端,在項(xiàng)目中新建AIDL文件演侯。這里我命名為:IImoocAIDL.aidl**

// IImoocAIDL.aidl
package com.mecury.aidltest;
// Declare any non-default types here with import statements
interface IImoocAIDL {    
    //計(jì)算num1 + num2    
    int add(int num1,int num2);
}

點(diǎn)擊同步按鈕(一定要先同步)姿染,查看是否生成IImoocAIDL文件。

aidl的生成.gif

生成的文件如下秒际,我寫了詳細(xì)的注釋悬赏,相信你能夠看懂:

生成的AIDL文件#IImoocAIDL.java:

這里來說一下AIDL通信的原理:首先看這個(gè)文件有一個(gè)叫做proxy的類,這是一個(gè)代理類娄徊,這個(gè)類運(yùn)行在客戶端中闽颇,其實(shí)AIDL實(shí)現(xiàn)的進(jìn)程間的通信并不是直接的通信,客戶端和服務(wù)端都是通過proxy來進(jìn)行通信的:客戶端調(diào)用的方法實(shí)際是調(diào)用是proxy中的方法寄锐,然后proxy通過和服務(wù)端通信將返回的結(jié)果返回給客戶端兵多。

/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: F:\\AS for android\\AIDLTest\\aidlclient\\src\\main\\aidl\\com\\mecury\\aidltest\\IImoocAIDL.aidl
 */
package com.mecury.aidltest;
// Declare any non-default types here with import statements

public interface IImoocAIDL extends android.os.IInterface {
    /**
     * Local-side IPC implementation stub class.
     */
    public static abstract class Stub extends android.os.Binder implements com.mecury.aidltest.IImoocAIDL {
        private static final java.lang.String DESCRIPTOR = "com.mecury.aidltest.IImoocAIDL"; //Binder的唯一標(biāo)識

        /**
         * Construct the stub at attach it to the interface.
         */
        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }

        /**
         * Cast an IBinder object into an com.mecury.aidltest.IImoocAIDL interface,
         * generating a proxy if needed.
         */
        //將服務(wù)端的Binder對象轉(zhuǎn)換成客戶需要的AIDL對象,轉(zhuǎn)換區(qū)分進(jìn)程锐峭,客戶端服務(wù)端位于同一進(jìn)程中鼠,返回服務(wù)端的
        //Stub對象本身;否則返回的是系統(tǒng)的封裝后的Stub.proxy對象沿癞。
        public static com.mecury.aidltest.IImoocAIDL asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.mecury.aidltest.IImoocAIDL))) {
                return ((com.mecury.aidltest.IImoocAIDL) iin);
            }
            return new com.mecury.aidltest.IImoocAIDL.Stub.Proxy(obj);
        }
        //返回當(dāng)前Binder對象
        @Override
        public android.os.IBinder asBinder() {
            return this;
        }

        //運(yùn)行在服務(wù)端的Binder線程池中
        @Override
        public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
            switch (code) {
                case INTERFACE_TRANSACTION: {
                    reply.writeString(DESCRIPTOR);
                    return true;
                }
                case TRANSACTION_add: {
                    data.enforceInterface(DESCRIPTOR);
                    //讀取客戶端傳遞過來再data中存儲的方法的參數(shù)
                    int _arg0;
                    _arg0 = data.readInt();
                    int _arg1;
                    _arg1 = data.readInt();
                    //調(diào)用方法
                    int _result = this.add(_arg0, _arg1);
                    //將計(jì)算結(jié)果寫入reply中
                    reply.writeNoException();
                    reply.writeInt(_result);
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags); //向Transact傳遞數(shù)據(jù)
        }
        
        //代理類,運(yùn)行在客戶端
        private static class Proxy implements com.mecury.aidltest.IImoocAIDL {
            private android.os.IBinder mRemote; //聲明一個(gè)IBinder對象

            Proxy(android.os.IBinder remote) {
                mRemote = remote;
            }
            //返回當(dāng)前Binder對象
            @Override
            public android.os.IBinder asBinder() {
                return mRemote;
            } 

            public java.lang.String getInterfaceDescriptor() {
                return DESCRIPTOR;
            }
            
            //客戶端調(diào)用此方法矛渴,傳遞進(jìn)來num1和num2兩個(gè)參數(shù)椎扬,
            @Override
            public int add(int num1, int num2) throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                int _result;
                try {
                    //向_data中寫入?yún)?shù)
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeInt(num1);
                    _data.writeInt(num2);
                    //通過transact方法向服務(wù)端傳遞參數(shù),并調(diào)用了方法具温,返回的結(jié)果寫入_reply中
                    mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readInt();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
        }
        //標(biāo)識位
        static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    }
    
    //計(jì)算num1 + num2
    public int add(int num1, int num2) throws android.os.RemoteException;
}

代碼中的幾個(gè)方法:
DESCRIPTION
Binderd的唯一標(biāo)識蚕涤,一般用當(dāng)前的類名表示。
asInterface(android.os.IBinder obj)
用于將服務(wù)端的Binder對象轉(zhuǎn)換為客戶端需要的AIDL接口類型的對象铣猩,轉(zhuǎn)換區(qū)分進(jìn)程揖铜,客戶端服務(wù)端位于同一進(jìn)程,返回服務(wù)端的 //Stub對象本身达皿;否則返回的是系統(tǒng)的封裝后的Stub.proxy對象天吓。
asBInder
返回Binder對象
onTransact
此方法運(yùn)行在服務(wù)端中的Binder線程池中,當(dāng)客戶端發(fā)起跨進(jìn)程請求時(shí)峦椰,遠(yuǎn)程請求會通過系統(tǒng)底層封裝后交由此方法處理龄寞。
Proxy#add
此方法運(yùn)行在客戶端,當(dāng)客戶端遠(yuǎn)程調(diào)用此方法時(shí)汤功,它的內(nèi)部實(shí)現(xiàn)是這樣的:首先創(chuàng)建該方法所需要的輸入型Parcel對象_data物邑、輸出型Parcel對象_reple和返回值對象_result,然后將該方法的參數(shù)信息寫入_data中;接著調(diào)用transact方法來發(fā)RPC請求,同時(shí)當(dāng)前線程掛起色解;然后服務(wù)端的onTransact方法會被調(diào)用茂嗓,直到RPC過程返回后,當(dāng)前線程繼續(xù)執(zhí)行科阎,并從_reply中取出RPC過程返回的結(jié)果述吸,寫入_result中。

2.新建一個(gè)客戶端File-》new--》new module--》phone & table module萧恕。這里我的命名為aidlclient.java
同樣要在客戶端創(chuàng)建AIDL文件刚梭,里面的包名和所在位置要求完全一樣。

3.在服務(wù)端創(chuàng)建一個(gè)Service用來監(jiān)聽客戶端的連接請求票唆。

public class IRemoteService extends Service {

    //客戶端綁定service時(shí)會執(zhí)行
    @Override
    public IBinder onBind(Intent intent) {
        return iBinder;
    }

    private IBinder iBinder = new IImoocAIDL.Stub(){

        @Override
        public int add(int num1, int num2) throws RemoteException {
            Log.e("TAG","收到了來自客戶端的請求" + num1 + "+" + num2 );
            return num1 + num2;
        }
    };
}

最后朴读,別忘記在AndroidManifest.xml中注冊該Service。

<service android:name=".IRemoteService"
            android:process=":remote"
            android:exported="true">
            <intent-filter>
                <action android:name="com.mecury.aidltest.IRomoteService"/>
            </intent-filter>
</service>

4.客戶端的編寫
activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <EditText
        android:id="@+id/num1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="+"/>
    <EditText
        android:id="@+id/num2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="="/>
    <TextView
        android:id="@+id/text"
        android:layout_width="match_parent"
        android:layout_height="30dp" />
    <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="計(jì)算"/>
</LinearLayout>

MainActivity.java

package com.mecury.aidlclient;

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.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import com.mecury.aidltest.IImoocAIDL;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private EditText num1;
    private EditText num2;
    private Button button;
    private TextView text;

    private IImoocAIDL iImoocAIDL;

    private ServiceConnection conn = new ServiceConnection() {

        //綁定服務(wù)走趋,回調(diào)onBind()方法
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            iImoocAIDL = IImoocAIDL.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            iImoocAIDL = null;
        }
    };

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

        bindService();
        initView();

    }

    private void initView() {
        num1 = (EditText) findViewById(R.id.num1);
        num2 = (EditText) findViewById(R.id.num2);
        button = (Button) findViewById(R.id.button);
        text = (TextView) findViewById(R.id.text);

        button.setOnClickListener(this);
    }


    @Override
    public void onClick(View v) {
        int num11 = Integer.parseInt(num1.getText().toString());
        int num22 = Integer.parseInt(num2.getText().toString());

        try {
            int res = iImoocAIDL.add(num11,num22);
            text.setText(num11 +"+"+ num22 +"="+ res);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    private void bindService() {

        Intent intent = new Intent();
        //綁定服務(wù)端的service
        intent.setAction("com.mecury.aidltest.IRomoteService");
        //新版本(5.0后)必須顯式intent啟動 綁定服務(wù)
        intent.setComponent(new ComponentName("com.mecury.aidltest","com.mecury.aidltest.IRemoteService"));
        //綁定的時(shí)候服務(wù)端自動創(chuàng)建
        bindService(intent,conn, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(conn);
    }
}

5.運(yùn)行代碼
先啟動服務(wù)端衅金,在啟動客戶端。

結(jié)果.gif

小結(jié):看完上面簿煌,是不是已經(jīng)對于AIDL的用法有個(gè)大概的了解氮唯。下面來看一個(gè)更為復(fù)雜的例子,這是《android開發(fā)藝術(shù)探索》中的例子: 建立一個(gè)圖書管理姨伟,能夠添加圖書惩琉、得到圖書列表、使用觀察者模式夺荒、當(dāng)新書到達(dá)時(shí)通知所有觀察者瞒渠。

4.AIDL高級示例

1.先看Book.java。需要注意的是技扼,AIDL能夠傳輸?shù)臄?shù)據(jù)類型有限制伍玖,這里必須將book序列化才能夠使用,同時(shí)Book類在客戶端和服務(wù)端都要這樣定義

Book.java
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);
    }

    protected Book(Parcel in) {
        bookId = in.readInt();
        bookName = in.readString();
    }

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

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

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

2.AIDL文件

Book.aidl
package com.mecury.aidltest2;
parcelable Book;
IOnNewBookArrivedListener.aidl
package com.mecury.aidltest2;

import com.mecury.aidltest2.book;
interface IOnNewBookArrivedListener {
     void OnNewBookArrivedListener(in Book book);
}```


##### *IBookManager.aidl*

package com.mecury.aidltest2;

import com.mecury.aidltest2.book;
import com.mecury.aidltest2.IOnNewBookArrivedListener;

interface IBookManager {
List<Book> getBookList();
void addBook(in Book book);
void registerListener(IOnNewBookArrivedListener listener);
void unregisterListener(IOnNewBookArrivedListener listener);
}```

3.服務(wù)端

BookManagerService.java
public class BookManagerService extends Service {

    private static final String TAG = "BMS";

    private AtomicBoolean mIsServiceDestoryed = new AtomicBoolean(false);
    private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<Book>();
    private RemoteCallbackList<IOnNewBookArrivedListener> mListeners = new RemoteCallbackList<>();

    //創(chuàng)建一個(gè)Binder對象
    private Binder mBinder = new IBookManager.Stub(){

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

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

        @Override
        public void registerListener(IOnNewBookArrivedListener listener) throws RemoteException {
            mListeners.register(listener);
        }

        @Override
        public void unregisterListener(IOnNewBookArrivedListener listener) throws RemoteException {
            mListeners.unregister(listener);
        }
    };

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

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }
    //將book添加到圖書列表中(mBookList)剿吻,并通知所有觀察者
    private void onNewBookArrived(Book book) throws RemoteException {
        mBookList.add(book);
        final int N = mListeners.beginBroadcast();
        Log.e("onNewBookArrived","registener listener size:" + N);
        for (int i = 0; i < N; i++){
            IOnNewBookArrivedListener l = mListeners.getBroadcastItem(i);
            if (l!=null){
                l.OnNewBookArrivedListener(book);
            }
        }
        mListeners.finishBroadcast();
    }
    //線程類窍箍。在每休眠5秒后,會自動添加一本書丽旅, 并通過OnNewBookArrived()方法通知所有觀察者椰棘。 
    private class serviceWork implements Runnable{

        @Override
        public void run() {
            while (!mIsServiceDestoryed.get()){
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                int bookId = mBookList.size() + 1;
                Book newBook = new Book(bookId,"new Book #" + bookId);

                try {
                    onNewBookArrived(newBook);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @Override
    public void onDestroy() {
        mIsServiceDestoryed.set(true);
        super.onDestroy();
    }
}
在里面我們發(fā)現(xiàn)幾處特殊的地方
1.CopyOnWriteArrayList:支持并發(fā)的讀寫,這里我們使用它來進(jìn)行自動的線程同步</br>
2.RemoteCallBackList:是系統(tǒng)專門提供的用于刪除跨進(jìn)程listener的接口魔招。它的工作原理其實(shí)很簡單:在它的內(nèi)部有一個(gè)Map結(jié)構(gòu)專門用來保存所有AIDL回調(diào)ArrayMap<IBinder, Callback> mCallback = new ArrayMap<IBinder, Callback>();,當(dāng)客戶端注冊listener時(shí)晰搀,會把listener的信息注冊到mCallBack中,其中key和value通過下面方式獲得:IBinder key = listener.asBinder();Callback value = new Callback(listener, cookie)。另外一點(diǎn)我們需要知道:對象是不能跨進(jìn)程傳輸?shù)陌彀撸瑢ο蟮目邕M(jìn)程傳輸過程實(shí)際是反序列化的過程外恕,這是我們Book類為什么要實(shí)現(xiàn)Parcelable接口的原因杆逗。在跨進(jìn)程傳輸中,Binder會把客戶端傳遞的對象重新轉(zhuǎn)化并生成另一對象鳞疲,當(dāng)我們注冊和解注冊的過程中使用的是同一個(gè)客戶端對象罪郊,但是通過Binder傳遞到服務(wù)端卻生成了兩個(gè)不同的對象。而RemoteCallBackList就是用來解決這個(gè)問題的尚洽,雖然所多次跨進(jìn)程傳輸客戶端的同一個(gè)對象會在服務(wù)端生成不同的對象悔橄,但在這些新生成的對象都有一個(gè)共同點(diǎn),那就是他們底層的Binder對象是同一個(gè)腺毫,利用這個(gè)癣疟,就可以實(shí)現(xiàn)上面無法實(shí)現(xiàn)的功能。當(dāng)客戶端解注冊時(shí)潮酒,我們只要遍歷所有的listener睛挚,找出那個(gè)和解注冊listener具有相同Binder對象服務(wù)器listener并把他刪除掉即可,這就是RemoteCallbackList為我們做的事情急黎。(對于這個(gè)看不明白的扎狱,可以看看《android 開發(fā)藝術(shù)探索》)

4.客戶端:

MainActivity.java
public class MainActivity extends AppCompatActivity {

    private static final String TAG = "BookManagerActivity";
    private IBookManager bookManager;
    private static final int MESSAGE_NEW_BOOK_ARRIVED = 1;

    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case MESSAGE_NEW_BOOK_ARRIVED:
                    Log.e(TAG, "received new book:" + msg.obj);
                    break;
                default:
                    super.handleMessage(msg);
            }

        }
    };

    private ServiceConnection mService = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            bookManager = IBookManager.Stub.asInterface(service);
            try {
                List<Book> list = bookManager.getBookList();
                Log.e(TAG, "query book list,list type:" + list.getClass().getCanonicalName());
                Log.e(TAG, "query book list:" + list.toString());
                Book newBook = new Book(3, "android進(jìn)階");
                bookManager.addBook(newBook);
                Log.e(TAG, "add book:" + newBook);
                List<Book> newList =  bookManager.getBookList();
                Log.e(TAG, "query book list:" + newList.toString());
                bookManager.registerListener(mNewBookArrivedListener);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            bookManager = null;
            Log.e(TAG, "binder died.");
        }
    };

    private IOnNewBookArrivedListener mNewBookArrivedListener = new IOnNewBookArrivedListener.Stub() {
        @Override
        public void OnNewBookArrivedListener(Book book) throws RemoteException {
            mHandler.obtainMessage(MESSAGE_NEW_BOOK_ARRIVED, book).sendToTarget();
        }
    };

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

        bindService();

    }

    private void bindService() {
        Intent intent = new Intent();
        intent.setAction("com.mecury.aidltest2.BookManagerService");
        intent.setComponent(new ComponentName("com.mecury.aidltest2", "com.mecury.aidltest2.BookManagerService"));
        bindService(intent, mService, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onDestroy() {
        if (bookManager != null && bookManager.asBinder().isBinderAlive()){
            Log.e(TAG, "unregister listener:" + mNewBookArrivedListener);
            try {
                bookManager.unregisterListener(mNewBookArrivedListener);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
        unbindService(mService);
        super.onDestroy();
    }
}

目錄結(jié)構(gòu):


目錄

運(yùn)行結(jié)果:

客戶端log:

06-29 22:52:29.438 17007-17007/com.mecury.client E/BookManagerActivity: query book list,list type:java.util.ArrayList
06-29 22:52:29.438 17007-17007/com.mecury.client E/BookManagerActivity: query book list:[1:Android, 2:Ios]
06-29 22:52:29.439 17007-17007/com.mecury.client E/BookManagerActivity: add book:3:android進(jìn)階
06-29 22:52:29.439 17007-17007/com.mecury.client E/BookManagerActivity: query book list:[1:Android, 2:Ios, 3:android進(jìn)階]
06-29 22:52:33.487 17007-17007/com.mecury.client E/BookManagerActivity: received new book:4:new Book #4
06-29 22:52:38.489 17007-17007/com.mecury.client E/BookManagerActivity: received new book:5:new Book #5
06-29 22:52:43.491 17007-17007/com.mecury.client E/BookManagerActivity: received new book:6:new Book #6
06-29 22:52:48.503 17007-17007/com.mecury.client E/BookManagerActivity: received new book:7:new Book #7```
*服務(wù)端log:*

06-29 22:52:33.487 17027-17044/com.mecury.aidltest2:remote E/onNewBookArrived: registener listener size:1
06-29 22:52:38.488 17027-17044/com.mecury.aidltest2:remote E/onNewBookArrived: registener listener size:1
06-29 22:52:43.490 17027-17044/com.mecury.aidltest2:remote E/onNewBookArrived: registener listener size:1
06-29 22:52:48.492 17027-17044/com.mecury.aidltest2:remote E/onNewBookArrived: registener listener size:1

## 5.一些補(bǔ)充
#####AIDL支持的數(shù)據(jù)類型
+ 基本數(shù)據(jù)類型(int、long勃教、char 等)
+ String 和 CharSequence
+ List:只支持ArrayList淤击,里面的每個(gè)元素都必須被AIDL支持。
+ Map: 只支持HashMap故源, 里面的每個(gè)元素都必須被AIDL支持污抬。
+ Parcelable: 所有實(shí)現(xiàn)了Parcelable接口的對象
+ AIDL: 所有的AIDL接口本身也可以在AIDL文件中使用

參考:
       1.《android開發(fā)藝術(shù)探索》
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市绳军,隨后出現(xiàn)的幾起案子壕吹,更是在濱河造成了極大的恐慌,老刑警劉巖删铃,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異踏堡,居然都是意外死亡猎唁,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進(jìn)店門顷蟆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來诫隅,“玉大人,你說我怎么就攤上這事帐偎≈鹞常” “怎么了?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵削樊,是天一觀的道長豁生。 經(jīng)常有香客問我兔毒,道長,這世上最難降的妖魔是什么甸箱? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任育叁,我火速辦了婚禮,結(jié)果婚禮上芍殖,老公的妹妹穿的比我還像新娘豪嗽。我一直安慰自己,他們只是感情好豌骏,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布龟梦。 她就那樣靜靜地躺著,像睡著了一般窃躲。 火紅的嫁衣襯著肌膚如雪计贰。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天框舔,我揣著相機(jī)與錄音蹦玫,去河邊找鬼。 笑死刘绣,一個(gè)胖子當(dāng)著我的面吹牛樱溉,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播纬凤,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼福贞,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了停士?” 一聲冷哼從身側(cè)響起挖帘,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎恋技,沒想到半個(gè)月后拇舀,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蜻底,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年骄崩,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片薄辅。...
    茶點(diǎn)故事閱讀 38,059評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡要拂,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出站楚,到底是詐尸還是另有隱情脱惰,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布窿春,位于F島的核電站拉一,受9級特大地震影響采盒,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜舅踪,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一纽甘、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧抽碌,春花似錦悍赢、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至痴颊,卻和暖如春赏迟,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蠢棱。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工锌杀, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人泻仙。 一個(gè)月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓糕再,卻偏偏與公主長得像,于是被迫代替她去往敵國和親玉转。 傳聞我的和親對象是個(gè)殘疾皇子突想,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評論 2 345

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