欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
[z]Android Service學(xué)習之AIDL, Parcelable和遠程服務(wù)
AIDL的作用
    由于每個(gè)應用程序都運行在自己的進(jìn)程空間,并且可以從應用程序UI運行另一個(gè)服務(wù)進(jìn)程,而且經(jīng)常會(huì )在不同的進(jìn)程間傳遞對象。在A(yíng)ndroid平臺,一個(gè)進(jìn)程通常不能訪(fǎng)問(wèn)另一個(gè)進(jìn)程的內存空間,所以要想對話(huà),需要將對象分解成操作系統可以理解的基本單元,并且有序的通過(guò)進(jìn)程邊界。
    通過(guò)代碼來(lái)實(shí)現這個(gè)數據傳輸過(guò)程是冗長(cháng)乏味的,Android提供了AIDL工具來(lái)處理這項工作。
 
    AIDL (Android Interface Definition Language) 是一種IDL 語(yǔ)言,用于生成可以在A(yíng)ndroid設備上兩個(gè)進(jìn)程之間進(jìn)行進(jìn)程間通信(interprocess communication, IPC)的代碼。如果在一個(gè)進(jìn)程中(例如Activity)要調用另一個(gè)進(jìn)程中(例如Service)對象的操作,就可以使用AIDL生成可序列化的參數。
    AIDL IPC機制是面向接口的,像COM或Corba一樣,但是更加輕量級。它是使用代理類(lèi)在客戶(hù)端和實(shí)現端傳遞數據。
  
選擇AIDL的使用場(chǎng)合
    官方文檔特別提醒我們何時(shí)使用AIDL是必要的:只有你允許客戶(hù)端從不同的應用程序為了進(jìn)程間的通信而去訪(fǎng)問(wèn)你的service,以及想在你的service處理多線(xiàn)程。
 
    如果不需要進(jìn)行不同應用程序間的并發(fā)通信(IPC),you should create your interface by implementing a Binder;或者你想進(jìn)行IPC,但不需要處理多線(xiàn)程的,則implement your interface using a Messenger。無(wú)論如何,在使用AIDL前,必須要理解如何綁定service——bindService。
 
    在設計AIDL接口前,要提醒的是,調用AIDL接口是直接的方法調用的,不是我們所想象的調用是發(fā)生在線(xiàn)程里。而調用(call)來(lái)自local進(jìn)程或者remote進(jìn)程,有什么區別呢?尤其是以下情況(引用原文,不作翻譯了,以免翻譯有誤):
  • 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接口文件,和普通的接口內容沒(méi)有什么特別,只是它的擴展名為.aidl。保存在src目錄下。如果其他應用程序需要IPC,則那些應用程序的src也要帶有這個(gè)文件。Android SDK tools就會(huì )在gen目錄自動(dòng)生成一個(gè)IBinder接口文件。service必須適當地實(shí)現這個(gè)IBinder接口。那么客戶(hù)端程序就能綁定這個(gè)service并在IPC時(shí)從IBinder調用方法。
    每個(gè)aidl文件只能定義一個(gè)接口,而且只能是接口的聲明和方法的聲明。
 
1.創(chuàng )建.aidl文件
     AIDL使用簡(jiǎn)單的語(yǔ)法來(lái)聲明接口,描述其方法以及方法的參數和返回值。這些參數和返回值可以是任何類(lèi)型,甚至是其他AIDL生成的接口。
    其中對于Java編程語(yǔ)言的基本數據類(lèi)型 (int, long, char, boolean等),String和CharSequence,集合接口類(lèi)型List和Map,不需要import 語(yǔ)句。
    而如果需要在A(yíng)IDL中使用其他AIDL接口類(lèi)型,需要import,即使是在相同包結構下。AIDL允許傳遞實(shí)現Parcelable接口的類(lèi),需要import.
    需要特別注意的是,對于非基本數據類(lèi)型,也不是String和CharSequence類(lèi)型的,需要有方向指示,包括in、out和inout,in表示由客戶(hù)端設置,out表示由服務(wù)端設置,inout是兩者均可設置。
    AIDL只支持接口方法,不能公開(kāi)static變量。
 
例如 (IMyService.aidl): 
package com.demo;

import com.demo.Person;

interface IMyService {
        void savePersonInfo(in Person person);
        List<Person> getAllPerson();
}

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

    newArray(int size) 創(chuàng )建一個(gè)類(lèi)型為T(mén),長(cháng)度為size的數組,僅一句話(huà)(return new T[size])即可。估計本方法是供外部類(lèi)反序列化本類(lèi)數組使用。
  
仔細觀(guān)察Person類(lèi)的代碼和上面所說(shuō)的內容:
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和原來(lái)實(shí)現的Parcelable 接口,開(kāi)頭的字母p一個(gè)小寫(xiě)一個(gè)大寫(xiě):
package com.demo;

parcelable Person;
 
     對于實(shí)現AIDL接口,官方還提醒我們:
    1. 調用者是不能保證在主線(xiàn)程執行的,所以從一調用的開(kāi)始就需要考慮多線(xiàn)程處理,以及確保線(xiàn)程安全;
    2. IPC調用是同步的。如果你知道一個(gè)IPC服務(wù)需要超過(guò)幾毫秒的時(shí)間才能完成地話(huà),你應該避免在A(yíng)ctivity的主線(xiàn)程中調用。也就是IPC調用會(huì )掛起應用程序導致界面失去響應,這種情況應該考慮單獨開(kāi)啟一個(gè)線(xiàn)程來(lái)處理。
    3. 拋出的異常是不能返回給調用者(跨進(jìn)程拋異常處理是不可取的)。
 
3. 客戶(hù)端獲取接口
    客戶(hù)端如何獲取AIDL接口呢?通過(guò)IMyService.Stub.asInterface(service)來(lái)得到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里面會(huì )找到這樣的代碼:
/**
* 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的綁定沒(méi)有什么不同:
if (mIsRemoteBound) {
        unbindService(mRemoteConnection);
}else{
        bindService(new Intent("com.demo.IMyService"),
                               mRemoteConnection, Context.BIND_AUTO_CREATE);
}

mIsRemoteBound = !mIsRemoteBound;
 
通過(guò)IPC調用/傳遞數據
    客戶(hù)端綁定service后就能通過(guò)IPC來(lái)調用/傳遞數據了,直接調用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權限
    如果Service在A(yíng)ndroidManifest.xml中聲明了全局的強制的訪(fǎng)問(wèn)權限,其他引用必須聲明權限才能來(lái)start,stop或bind這個(gè)service.
     另外,service可以通過(guò)權限來(lái)保護她的IPC方法調用,通過(guò)調用checkCallingPermission(String)方法來(lái)確??梢詧绦羞@個(gè)操作。

 AndroidManifest.xml的Service元素
<service android:name=".RemoteService" android:process=":remote">
        <intent-filter>
                <action android:name="com.demo.IMyService" />
        </intent-filter>
</service>
    這里的android:process=":remote",一開(kāi)始我沒(méi)有添加的,在同一個(gè)程序里使用IPC,即同一個(gè)程序作為客戶(hù)端/服務(wù)器端,結果運行mRemoteService = IMyService.Stub.asInterface(service);時(shí)提示空指針異常。觀(guān)察了人家的在不同程序里進(jìn)行IPC的代碼,也是沒(méi)有這個(gè)android:process=":remote"的。后來(lái)在官方文檔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.
 也就是說(shuō)android:process=":remote",代表在應用程序里,當需要該service時(shí),會(huì )自動(dòng)創(chuàng )建新的進(jìn)程。而如果是android:process="remote",沒(méi)有“:”分號的,則創(chuàng )建全局進(jìn)程,不同的應用程序共享該進(jìn)程。
 
以上內容結合了不少網(wǎng)絡(luò )文章,包括來(lái)自
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
android跨進(jìn)程通信(IPC):使用AIDL
Binder與AIDL服務(wù)
Android 使用【AIDL】調用外部服務(wù)
使用AIDL(Android接口描述語(yǔ)言)設計和使用遠程接口
Service知識點(diǎn)整理
耗時(shí)兩年,Android多進(jìn)程從頭講到尾(萬(wàn)字總結,建議收藏)
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久