<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                ##2.1 Android IPC簡介 (1)任何一個操作系統都需要有相應的IPC機制,Linux上可以通過命名通道、共享內存、信號量等來進行進程間通信。Android系統不僅可以使用了Binder機制來實現IPC,還可以使用Socket實現任意兩個終端之間的通信。 ## 2.2 Android中的多進程模式 (1)通過給四大組件指定`android:process`屬性就可以開啟多進程模式,默認進程的進程名是包名packageName,進程名以`:`開頭的進程屬于當前應用的私有進程,其他應用的組件不可以和它跑在同一個進程中,而進程名不以`:`開頭的進程屬于全局進程,其他應用通過`ShareUID`方法可以和它跑在同一個進程中。 ~~~ android:process=":xyz" //進程名是 packageName:xyz android:process="aaa.bbb.ccc" //進程名是 aaa.bbb.ccc ~~~ (2)Android系統會為每個應用分配一個唯一的UID,具有相同UID的應用才能共享數據。兩個應用通過ShareUID跑在同一個進程中是有要求的,需要這兩個應用有相同的ShareUID并且簽名相同才可以。?在這種情況下,它們可以相互訪問對方的私有數據,比如data目錄、組件信息等,不管它們是否跑在同一個進程中。如果它們跑在同一個進程中,還可以共享內存數據,它們看起來就像是一個應用的兩個部分。 (3)android系統會為每個進程分配一個獨立的虛擬機,不同的虛擬機在內存分配上有不同的地址空間,所以不同的虛擬機中訪問同一個類的對象會產生多個副本。 (4)使用多線程容易造成以下幾個問題: 1.靜態成員和單例模式完全失效; 2.線程同步機制完全失效:無論鎖對象還是鎖全局對象都無法保證線程同步; 3.`SharedPreferences`的可靠性下降:SharedPreferences不支持并發讀寫; 4.Application會多次創建:當一個組件跑在一個新的進程的時候,系統要在創建新的進程的同時分配獨立的虛擬機,應用會重新啟動一次,也就會創建新的Application。運行在同一個進程中的組件是屬于同一個虛擬機和同一個Application。 同一個應用的不同組件,如果它們運行在不同進程中,那么和它們分別屬于兩個應用沒有本質區別。 ## 2.3 IPC基礎概念介紹 (1)`Serializable`接口是Java中為對象提供標準的序列化和反序列化操作的接口,而`Parcelable`接口是Android提供的序列化方式的接口。 (2)`serialVersionUId`是一串long型數字,主要是用來輔助序列化和反序列化的,原則上序列化后的數據中的serialVersionUId只有和當前類的serialVersionUId相同才能夠正常地被反序列化。 serialVersionUId的詳細工作機制:序列化的時候系統會把當前類的serialVersionUId寫入序列化的文件中,當反序列化的時候系統會去檢測文件中的serialVersionUId,看它是否和當前類的serialVersionUId一致,如果一致就說明序列化的類的版本和當前類的版本是相同的,這個時候可以成功反序列化;否則說明版本不一致無法正常反序列化。一般來說,我們應該手動指定serialVersionUId的值。 1.靜態成員變量屬于類不屬于對象,所以不參與序列化過程; 2.聲明為`transient`的成員變量不參與序列化過程。 (3)`Parcelable`接口內部包裝了可序列化的數據,可以在Binder中自由傳輸,`Parcelable`主要用在內存序列化上,可以直接序列化的有Intent、Bundle、Bitmap以及List和Map等等,下面是一個實現了`Parcelable`接口的示例 ~~~ public class Book implements Parcelable { public int bookId; public String bookName; public Book() { } public Book(int bookId, String bookName) { this.bookId = bookId; this.bookName = bookName; } //“內容描述”,如果含有文件描述符返回1,否則返回0,幾乎所有情況下都是返回0 public int describeContents() { return 0; } //實現序列化操作,flags標識只有0和1,1表示標識當前對象需要作為返回值返回,不能立即釋放資源,幾乎所有情況都為0 public void writeToParcel(Parcel out, int flags) { out.writeInt(bookId); out.writeString(bookName); } //實現反序列化操作 public static final Parcelable.Creator<Book> CREATOR = new Parcelable.Creator<Book>() { //從序列化后的對象中創建原始對象 public Book createFromParcel(Parcel in) { return new Book(in); } public Book[] newArray(int size) {//創建指定長度的原始對象數組 return new Book[size]; } }; private Book(Parcel in) { bookId = in.readInt(); bookName = in.readString(); } } ~~~ (4)`Binder`是Android中的一個類,它實現了`IBinder`接口。從IPC角度看,Binder是Android中一種跨進程通信的方式;Binder還可以理解為虛擬的物理設備,它的設備驅動是`/dev/binder`;從Framework層角度看,Binder是ServiceManager連接各種`Manager`和相應的`ManagerService`的橋梁;從Android應用層來說,Binder是客戶端和服務端進行通信的媒介,當`bindService`的時候,服務端會返回一個包含了服務端業務調用的Binder對象,通過這個Binder對象,客戶端就可以獲取服務端提供的服務或者數據,這里的服務包括普通服務和基于AIDL的服務。 在Android開發中,Binder主要用在Service中,包括AIDL和Messenger,其中普通Service中的Binder不涉及進程間通信,較為簡單;而Messenger的底層其實是AIDL,正是Binder的核心工作機制。 (5)aidl工具根據aidl文件自動生成的java接口的解析:首先,它聲明了幾個接口方法,同時還聲明了幾個整型的id用于標識這些方法,id用于標識在`transact`過程中客戶端所請求的到底是哪個方法;接著,它聲明了一個內部類`Stub`,這個Stub就是一個`Binder`類,當客戶端和服務端都位于同一個進程時,方法調用不會走跨進程的`transact`過程,而當兩者位于不同進程時,方法調用需要走transact過程,這個邏輯由Stub內部的代理類`Proxy`來完成。 所以,這個接口的核心就是它的內部類Stub和Stub內部的代理類Proxy。?下面分析其中的方法: 1.`asInterface(android.os.IBinder obj)`:用于將服務端的Binder對象轉換成客戶端所需的AIDL接口類型的對象,這種轉換過程是區分進程的,如果客戶端和服務端是在同一個進程中,那么這個方法返回的是服務端的`Stub`對象本身,否則返回的是系統封裝的`Stub.Proxy`對象。 2.`asBinder`:返回當前Binder對象。 3.`onTransact`:這個方法運行在服務端中的Binder線程池中,當客戶端發起跨進程請求時,遠程請求會通過系統底層封裝后交由此方法來處理。 這個方法的原型是`public Boolean onTransact(int code, Parcelable data, Parcelable reply, int flags)` 服務端通過`code`可以知道客戶端請求的目標方法,接著從`data`中取出所需的參數,然后執行目標方法,執行完畢之后,將結果寫入到`reply`中。如果此方法返回false,說明客戶端的請求失敗,利用這個特性可以做權限驗證(即驗證是否有權限調用該服務)。 4.`Proxy#[Method]`:代理類中的接口方法,這些方法運行在客戶端,當客戶端遠程調用此方法時,它的內部實現是:首先創建該方法所需要的參數,然后把方法的參數信息寫入到`_data`中,接著調用`transact`方法來發起RPC請求,同時當前線程掛起;然后服務端的`onTransact`方法會被調用,直到RPC過程返回后,當前線程繼續執行,并從`_reply`中取出RPC過程的返回結果,最后返回`_reply`中的數據。 如果搞清楚了自動生成的接口文件的結構和作用之后,其實是可以不用通過AIDL而直接實現Binder的,[主席寫的示例代碼](https://github.com/singwhatiwanna/android-art-res/blob/master/Chapter_2/src/com/ryg/chapter_2/manualbinder/BookManagerImpl.java) (6)Binder的兩個重要方法`linkToDeath`和`unlinkToDeath` Binder運行在服務端,如果由于某種原因服務端異常終止了的話會導致客戶端的遠程調用失敗,所以Binder提供了兩個配對的方法`linkToDeath`和`unlinkToDeath`,通過`linkToDeath`方法可以給Binder設置一個死亡代理,當Binder死亡的時候客戶端就會收到通知,然后就可以重新發起連接請求從而恢復連接了。 如何給Binder設置死亡代理呢? 1.聲明一個`DeathRecipient`對象,`DeathRecipient`是一個接口,其內部只有一個方法`bindeDied`,實現這個方法就可以在Binder死亡的時候收到通知了。 ~~~ private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() { @Override public void binderDied() { if (mRemoteBookManager == null) return; mRemoteBookManager.asBinder().unlinkToDeath(mDeathRecipient, 0); mRemoteBookManager = null; // TODO:這里重新綁定遠程Service } }; ~~~ 2.在客戶端綁定遠程服務成功之后,給binder設置死亡代理 ~~~ mRemoteBookManager.asBinder().linkToDeath(mDeathRecipient, 0); ~~~ ## 2.4 Android中的IPC方式 (1)使用Bundle:Bundle實現了Parcelable接口,Activity、Service和Receiver都支持在Intent中傳遞Bundle數據。 (2)使用文件共享:這種方式簡單,適合在對數據同步要求不高的進程之間進行通信,并且要妥善處理并發讀寫的問題。 `SharedPreferences`是一個特例,雖然它也是文件的一種,但是由于系統對它的讀寫有一定的緩存策略,即在內存中會有一份SharedPreferences文件的緩存,因此在多進程模式下,系統對它的讀寫就變得不可靠,當面對高并發讀寫訪問的時候,有很大幾率會丟失數據,因此,不建議在進程間通信中使用SharedPreferences。 (3)使用Messenger:`Messenger`是一種輕量級的IPC方案,它的底層實現就是AIDL。Messenger是以串行的方式處理請求的,即服務端只能一個個處理,不存在并發執行的情形,詳細的示例見原書。 (4)使用AIDL 大致流程:首先建一個Service和一個AIDL接口,接著創建一個類繼承自AIDL接口中的Stub類并實現Stub類中的抽象方法,在Service的onBind方法中返回這個類的對象,然后客戶端就可以綁定服務端Service,建立連接后就可以訪問遠程服務端的方法了。 1.AIDL支持的數據類型:基本數據類型、`String`和`CharSequence`、`ArrayList`、`HashMap`、`Parcelable`以及`AIDL`; 2.某些類即使和AIDL文件在同一個包中也要顯式import進來; 3.AIDL中除了基本數據類,其他類型的參數都要標上方向:`in`、`out`或者`inout`; 4.AIDL接口中支持方法,不支持聲明靜態變量; 5.為了方便AIDL的開發,建議把所有和AIDL相關的類和文件全部放入同一個包中,這樣做的好處是,當客戶端是另一個應用的時候,可以直接把整個包復制到客戶端工程中。 6.`RemoteCallbackList`是系統專門提供的用于刪除跨進程Listener的接口。RemoteCallbackList是一個泛型,支持管理任意的AIDL接口,因為所有的AIDL接口都繼承自`IInterface`接口。 (5)使用ContentProvider 1.ContentProvider主要以表格的形式來組織數據,并且可以包含多個表; 2.ContentProvider還支持文件數據,比如圖片、視頻等,系統提供的`MediaStore`就是文件類型的ContentProvider; 3.ContentProvider對底層的數據存儲方式沒有任何要求,可以是SQLite、文件,甚至是內存中的一個對象都行; 4.要觀察ContentProvider中的數據變化情況,可以通過`ContentResolver`的`registerContentObserver`方法來注冊觀察者; (6)使用Socket Socket是網絡通信中“套接字”的概念,分為流式套接字和用戶數據包套接字兩種,分別對應網絡的傳輸控制層的TCP和UDP協議。 ## 2.5 Binder連接池 (1)當項目規模很大的時候,創建很多個Service是不對的做法,因為service是系統資源,太多的service會使得應用看起來很重,所以最好是將所有的AIDL放在同一個Service中去管理。整個工作機制是:每個業務模塊創建自己的AIDL接口并實現此接口,這個時候不同業務模塊之間是不能有耦合的,所有實現細節我們要單獨開來,然后向服務端提供自己的唯一標識和其對應的Binder對象;對于服務端來說,只需要一個Service,服務端提供一個`queryBinder`接口,這個接口能夠根據業務模塊的特征來返回相應的Binder對象給它們,不同的業務模塊拿到所需的Binder對象后就可以進行遠程方法調用了。 Binder連接池的主要作用就是將每個業務模塊的Binder請求統一轉發到遠程Service去執行,從而避免了重復創建Service的過程。 (2)作者實現的Binder連接池[`BinderPool`的實現源碼](https://github.com/singwhatiwanna/android-art-res/blob/master/Chapter_2/src/com/ryg/chapter_2/binderpool/BinderPool.java),建議在AIDL開發工作中引入BinderPool機制。 ## 2.6 選用合適的IPC方式 ![](https://box.kancloud.cn/2015-12-10_56692ec1c55ed.png)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看