• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            life02

              C++博客 :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
              197 隨筆 :: 3 文章 :: 37 評論 :: 0 Trackbacks
            http://android.blog.51cto.com/268543/537684
            AIDL的作用
                由于每個應(yīng)用程序都運行在自己的進(jìn)程空間,并且可以從應(yīng)用程序UI運行另一個服務(wù)進(jìn)程,而且經(jīng)常會在不同的進(jìn)程間傳遞對象。在Android平臺,一 個進(jìn)程通常不能訪問另一個進(jìn)程的內(nèi)存空間,所以要想對話,需要將對象分解成操作系統(tǒng)可以理解的基本單元,并且有序的通過進(jìn)程邊界。
                通過代碼來實現(xiàn)這個數(shù)據(jù)傳輸過程是冗長乏味的,Android提供了AIDL工具來處理這項工作。
             
                AIDL (Android Interface Definition Language) 是一種IDL 語言,用于生成可以在Android設(shè)備上兩個進(jìn)程之間進(jìn)行進(jìn)程間通信(interprocess communication, IPC)的代碼。如果在一個進(jìn)程中(例如Activity)要調(diào)用另一個進(jìn)程中(例如Service)對象的操作,就可以使用AIDL生成可序列化的參 數(shù)。
                AIDL IPC機(jī)制是面向接口的,像COM或Corba一樣,但是更加輕量級。它是使用代理類在客戶端和實現(xiàn)端傳遞數(shù)據(jù)。
              
            選擇AIDL的使用場合
                官方文檔特別提醒我們何時使用AIDL是必要的:只有你允許客戶端從不同的應(yīng)用程序為了進(jìn)程間的通信而去訪問你的service,以及想在你的service處理多線程。
             
                如果不需要進(jìn)行不同應(yīng)用程序間的并發(fā)通信(IPC),you should create your interface by implementing a Binder;或者你想進(jìn)行IPC,但不需要處理多線程的,則implement your interface using a Messenger。無論如何,在使用AIDL前,必須要理解如何綁定service——bindService。
             
                在設(shè)計AIDL接口前,要提醒的是,調(diào)用AIDL接口是直接的方法調(diào)用的,不是我們所想象的調(diào)用是發(fā)生在線程里。而調(diào)用(call)來自local進(jìn)程或者remote進(jìn)程,有什么區(qū)別呢?尤其是以下情況(引用原文,不作翻譯了,以免翻譯有誤):
            • Calls made from the local process are executed in the same thread that is making the call. If this is your main UI thread, that thread continues to execute in the AIDL interface. If it is another thread, that is the one that executes your code in the service. Thus, if only local threads are accessing the service, you can completely control which threads are executing in it (but if that is the case, then you shouldn't be using AIDL at all, but should instead create the interface by implementing a Binder).
            • Calls from a remote process are dispatched from a thread pool the platform maintains inside of your own process. You must be prepared for incoming calls from unknown threads, with multiple calls happening at the same time. In other words, an implementation of an AIDL interface must be completely thread-safe.
            • The oneway keyword modifies the behavior of remote calls. When used, a remote call does not block; it simply sends the transaction data and immediately returns. The implementation of the interface eventually receives this as a regular call from the Binder thread pool as a normal remote call. If oneway is used with a local call, there is no impact and the call is still synchronous.

            定義AIDL接口
                AIDL接口文件,和普通的接口內(nèi)容沒有什么特別,只是它的擴(kuò)展名為.aidl。保存在src目錄下。如果其他應(yīng)用程序需要IPC,則那些應(yīng)用程序的src也要帶有這個文件。Android SDK tools就會在gen目錄自動生成一個IBinder接口文件。service必須適當(dāng)?shù)貙崿F(xiàn)這個IBinder接口。那么客戶端程序就能綁定這個service并在IPC時從IBinder調(diào)用方法。
                每個aidl文件只能定義一個接口,而且只能是接口的聲明和方法的聲明。
             
            1.創(chuàng)建.aidl文件
                 AIDL使用簡單的語法來聲明接口,描述其方法以及方法的參數(shù)和返回值。這些參數(shù)和返回值可以是任何類型,甚至是其他AIDL生成的接口。
                其中對于Java編程語言的基本數(shù)據(jù)類型 (int, long, char, boolean等),String和CharSequence,集合接口類型List和Map,不需要import 語句。
                而如果需要在AIDL中使用其他AIDL接口類型,需要import,即使是在相同包結(jié)構(gòu)下。AIDL允許傳遞實現(xiàn)Parcelable接口的類,需要import.
                需要特別注意的是,對于非基本數(shù)據(jù)類型,也不是String和CharSequence類型的,需要有方向指示,包括in、out和inout,in表示由客戶端設(shè)置,out表示由服務(wù)端設(shè)置,inout是兩者均可設(shè)置。
                AIDL只支持接口方法,不能公開static變量。
             
            例如 (IMyService.aidl): 
            package com.demo;

            import com.demo.Person;

            interface IMyService {
                    void savePersonInfo(in Person person);
                    List<Person> getAllPerson();
            }
            2.實現(xiàn)接口
                創(chuàng)建一個類實現(xiàn)剛才那個aidl的接口:
            public class RemoteService extends Service {

                    private LinkedList<Person> personList = new LinkedList<Person>();
                    
                    @Override
                    public IBinder onBind(Intent intent) {
                            return mBinder;
                    }

                    private final IMyService.Stub mBinder = new IMyService.Stub(){

                            @Override
                            public void savePersonInfo(Person person) throws RemoteException {
                                    if (person != null){
                                            personList.add(person);
                                    }
                            }

                            @Override
                            public List<Person> getAllPerson() throws RemoteException {
                                    return personList;
                            }
                    };
            }
             
                這里會看到有一個名為IMyService.Stub類,查看aidl文件生成的Java文件源代碼就能發(fā)現(xiàn)有這么一段代碼:
            /** Local-side IPC implementation stub class. */
            public static abstract class Stub extends android.os.Binder implements com.demo.IMyService
                原來Stub類就是繼承于Binder類,也就是說RemoteService類和普通的Service類沒什么不同,只是所返回的IBinder對象比較特別,是一個實現(xiàn)了AIDL接口的Binder。
             
                接下來就是關(guān)于所傳遞的數(shù)據(jù)Bean——Person類,是一個序列化的類,這里使用Parcelable 接口來序列化,是Android提供的一個比Serializable 效率更高的序列化類。
                Parcelable需要實現(xiàn)三個函數(shù):
                1) void writeToParcel(Parcel dest, int flags) 將需要序列化存儲的數(shù)據(jù)寫入外部提供的Parcel對象dest。而看了網(wǎng)上的代碼例子,個人猜測,讀取Parcel數(shù)據(jù)的次序要和這里的write次序一致,否則可能會讀錯數(shù)據(jù)。具體情況我沒試驗過!
                2) describeContents() 沒搞懂有什么用,反正直接返回0也可以
                3) static final Parcelable.Creator對象CREATOR  這個CREATOR命名是固定的,而它對應(yīng)的接口有兩個方法:
                createFromParcel(Parcel source) 實現(xiàn)從source創(chuàng)建出JavaBean實例的功能

                newArray(int size) 創(chuàng)建一個類型為T,長度為size的數(shù)組,僅一句話(return new T[size])即可。估計本方法是供外部類反序列化本類數(shù)組使用。
              
            仔細(xì)觀察Person類的代碼和上面所說的內(nèi)容:
            public class Person implements Parcelable {

                    private String name;
                    private String telNumber;
                    private int age;

                    public Person() {}

                    public Person(Parcel pl){
                            name = pl.readString();
                            telNumber = pl.readString();
                            age = pl.readInt();
                    }

                    public String getName() {
                            return name;
                    }

                    public void setName(String name) {
                            this.name = name;
                    }

                    public String getTelNumber() {
                            return telNumber;
                    }

                    public void setTelNumber(String telNumber) {
                            this.telNumber = telNumber;
                    }

                    public int getAge() {
                            return age;
                    }

                    public void setAge(int age) {
                            this.age = age;
                    }

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

                    @Override
                    public void writeToParcel(Parcel dest, int flags) {
                            dest.writeString(name);
                            dest.writeString(telNumber);
                            dest.writeInt(age);
                    }

                    public static final Parcelable.Creator<Person> CREATOR = new Parcelable.Creator<Person>() {

                            @Override
                            public Person createFromParcel(Parcel source) {
                                    return new Person(source);
                            }

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

                    };
            }

            然后創(chuàng)建Person.aidl文件,注意這里的parcelable和原來實現(xiàn)的Parcelable 接口,開頭的字母p一個小寫一個大寫:
            package com.demo;

            parcelable Person;
             
                 對于實現(xiàn)AIDL接口,官方還提醒我們:
                1. 調(diào)用者是不能保證在主線程執(zhí)行的,所以從一調(diào)用的開始就需要考慮多線程處理,以及確保線程安全;
                2. IPC調(diào)用是同步的。如果你知道一個IPC服務(wù)需要超過幾毫秒的時間才能完成地話,你應(yīng)該避免在Activity的主線程中調(diào)用。也就是IPC調(diào)用會掛起應(yīng)用程序?qū)е陆缑媸ロ憫?yīng),這種情況應(yīng)該考慮單獨開啟一個線程來處理。
                3. 拋出的異常是不能返回給調(diào)用者(跨進(jìn)程拋異常處理是不可取的)。
             
            3. 客戶端獲取接口
                客戶端如何獲取AIDL接口呢?通過IMyService.Stub.asInterface(service)來得到IMyService對象:
            private IMyService mRemoteService;

            private ServiceConnection mRemoteConnection = new ServiceConnection() {    
                    public void onServiceConnected(ComponentName className, IBinder service) {    
                            mRemoteService = IMyService.Stub.asInterface(service);    
                    }    

                    public void onServiceDisconnected(ComponentName className) {    
                            mRemoteService = null;    
                    }    
            };
             在生成的IMyService.java里面會找到這樣的代碼:
            /**
            * Cast an IBinder object into an com.demo.IMyService interface,
            * generating a proxy if needed.
            */
            public static com.demo.IMyService asInterface(android.os.IBinder obj) {...}
             
            而service的綁定沒有什么不同:
            if (mIsRemoteBound) {
                    unbindService(mRemoteConnection);
            }else{
                    bindService(new Intent("com.demo.IMyService"),
                                           mRemoteConnection, Context.BIND_AUTO_CREATE);
            }

            mIsRemoteBound = !mIsRemoteBound;
             
            通過IPC調(diào)用/傳遞數(shù)據(jù)
                客戶端綁定service后就能通過IPC來調(diào)用/傳遞數(shù)據(jù)了,直接調(diào)用service對象的接口方法:
            addPersonButton.setOnClickListener(
                            new View.OnClickListener(){
                                    private int index = 0;

                                    @Override
                                    public void onClick(View view) {
                                            Person person = new Person();
                                            index = index + 1;
                                            person.setName("Person" + index);
                                            person.setAge(20);
                                            person.setTelNumber("123456"); 
                                            try {
                                                    mRemoteService.savePersonInfo(person);
                                            } catch (RemoteException e) {
                                                    e.printStackTrace();
                                            } 
                                    }
                            });

            listPersonButton.setOnClickListener(
                            new View.OnClickListener(){

                                    @Override
                                    public void onClick(View view) {
                                            List<Person> list = null; 

                                            try {
                                                    list = mRemoteService.getAllPerson();
                                            } catch (RemoteException e) {
                                                    e.printStackTrace();
                                            } 

                                            if (list != null){
                                                    StringBuilder text = new StringBuilder();

                                                    for(Person person : list){
                                                            text.append("\nPerson name:");
                                                            text.append(person.getName());
                                                            text.append("\n             age :");
                                                            text.append(person.getAge());
                                                            text.append("\n tel number:");
                                                            text.append(person.getTelNumber());
                                                    }

                                                    inputPersonEdit.setText(text);
                                            }else {
                                                    Toast.makeText(ServiceActivity.this, "get data error",
                                                                    Toast.LENGTH_SHORT).show();
                                            }
                                    }
                            });

             Permission權(quán)限
                如果Service在AndroidManifest.xml中聲明了全局的強(qiáng)制的訪問權(quán)限,其他引用必須聲明權(quán)限才能來start,stop或bind這個service.
                 另外,service可以通過權(quán)限來保護(hù)她的IPC方法調(diào)用,通過調(diào)用checkCallingPermission(String)方法來確保可以執(zhí)行這個操作。

             AndroidManifest.xml的Service元素
            <service android:name=".RemoteService" android:process=":remote">
                    <intent-filter>
                            <action android:name="com.demo.IMyService" />
                    </intent-filter>
            </service>
                這里的android:process=":remote",一開始我沒有添加的,在同一個程序里使用IPC,即同一個程序作為客戶端/服務(wù)器端,結(jié)果運 行mRemoteService = IMyService.Stub.asInterface(service);時提示空指針異常。觀察了人家的在不同程序里進(jìn)行IPC的代碼,也是沒有這 個android:process=":remote"的。后來在官方文檔http://androidappdocs.appspot.com/guide/topics/manifest/service-element.html里了解到(留意第二段文字):
            android:process
            The name of the process where the service is to run. Normally, all components of an application run in the default process created for the application. It has the same name as the application package. The <application> element's process attribute can set a different default for all components. But component can override the default with its own process attribute, allowing you to spread your application across multiple processes.
             
            If the name assigned to this attribute begins with a colon (':'), a new process, private to the application, is created when it's needed and the service runs in that process. If the process name begins with a lowercase character, the service will run in a global process of that name, provided that it has permission to do so. This allows components in different applications to share a process, reducing resource usage.
             也就是說android:process=":remote",代表在應(yīng)用程序里,當(dāng)需要該service時,會自動創(chuàng)建新的進(jìn)程。而如果是android:process="remote",沒有“:”分號的,則創(chuàng)建全局進(jìn)程,不同的應(yīng)用程序共享該進(jìn)程。
             
            以上內(nèi)容結(jié)合了不少網(wǎng)絡(luò)文章,包括來自
            posted on 2012-03-06 11:49 life02 閱讀(475) 評論(0)  編輯 收藏 引用 所屬分類: android組件學(xué)習(xí)
            日本免费久久久久久久网站| 无码人妻久久一区二区三区| 国产亚洲精品美女久久久| 久久国产V一级毛多内射| 97久久精品人人澡人人爽| 久久精品国产网红主播| 久久久久久久亚洲Av无码| 亚洲国产精品成人久久| 亚洲精品无码久久久久去q| 亚洲愉拍99热成人精品热久久| 久久亚洲精品无码aⅴ大香| 久久久www免费人成精品| 亚洲中文字幕无码一久久区| 久久久久亚洲AV无码永不| 久久天天躁狠狠躁夜夜网站| 久久人人爽人人爽人人AV东京热| 久久精品国产亚洲AV忘忧草18| 无码人妻少妇久久中文字幕蜜桃 | 影音先锋女人AV鲁色资源网久久| 国产精品久久久久a影院| 天天爽天天狠久久久综合麻豆| 久久综合88熟人妻| 精品久久久久久99人妻| 思思久久精品在热线热| 999久久久免费精品国产| 99久久国产主播综合精品| 婷婷国产天堂久久综合五月| 97久久国产综合精品女不卡| 久久久久久a亚洲欧洲aⅴ| 一个色综合久久| 国产成人久久激情91| 久久久久女教师免费一区| 亚洲精品乱码久久久久久蜜桃图片 | 久久精品综合一区二区三区| 欧美日韩精品久久久久| 国产精品视频久久久| 久久午夜免费视频| 国产午夜久久影院| 国产美女亚洲精品久久久综合| 香蕉久久夜色精品国产小说| 久久中文字幕人妻熟av女|