乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      三步掌握 Android 中的 AIDL

       codingSmart 2021-10-22

      第一步 創(chuàng)建 aidl 接口文件

      AndroidStudio 中直接右鍵創(chuàng)建,或者自己一步步建目錄嘍。

      創(chuàng)建完成后會生成一個 XXX.aidl接口文件,我們需要根據(jù)需求在這個接口類中添加接口。

      在看接口怎么寫前,先記住以下三點:

      支持的參數(shù)類型

      1. 八種基本數(shù)據(jù)類型;

      2. String、CharSequence;

      3. List、Map,它們中的數(shù)據(jù)類型也應該是AIDL支持的;

      4. 實現(xiàn)Parcelabel的引用類型。


      自定義引用類型使用

      如果要使用自定義的數(shù)據(jù)類型,需要先為它也生成一個aidl文件,里面內(nèi)容只需兩行:

      AIDL的包名; parcelable 類名;

      例如:

      package com.coorchice.coorchicelibone; parcelable Role;

      接著就可以創(chuàng)建對應的java數(shù)據(jù)類了,然后實現(xiàn)Parcelable接口,注意包名需要和aidl一模一樣!如果你對自定義類型使用了in或者inout標識符的話,你必須再給自定義類實現(xiàn) readFromParcel()方法。比如:

      public void readFromParcel(Parcel in) {  name = in.readString();  skill = in.readString(); }

      然后在定義 aidl 接口時,一定要記得手動寫一下自定義引用類的import!

      參數(shù)修飾符

      • in: 表示參數(shù)數(shù)據(jù)只能由客戶端傳遞到服務端,基本類型就默認只支持in修飾符。

      • out:表示參數(shù)數(shù)據(jù)只能由服務端傳遞到客戶端。即服務端如果修改了參數(shù)對象的值,那么客戶端的值也會變化,但是服務端無法讀取到客戶端對象的值。

      • inout:表示參數(shù)數(shù)據(jù)能夠雙向傳遞。


      定義服務接口

      現(xiàn)在,我們可以開始定義服務接口了!這里定義的服務接口就是后面我們需要在客戶端調(diào)用的。

      CoorChice 定義了3個接口,接著編譯一下。然后編譯器會自動根據(jù)我們定義的接口生成對應的類。

      注意:自定義的類必須加in、out、inout等標識符,否則會報錯!


      編譯后生成的類解析

      編譯之后編譯器自動幫我們生成了一個服務接口類名.Stub的抽象類,它繼承自 Binder,然后實現(xiàn)了我們定義的服務接口(注意我們的服務接口實現(xiàn)了IInterface接口)。嗯,重點是它是一個Binder!它就是我們用來進行 Binder 通訊的!

      其實,Android 的 AIDL 就是讓編譯器幫助我們生成一個實現(xiàn)了我們接口的 Binder,以幫助我們簡化開發(fā)。當然,如果你了解原理的話,也可以自己寫。

      下面我們一步一步來看看這編譯器生成的類都有些什么?

      1. 服務接口實現(xiàn)IInterface

      public interface AIDLDemo extends android.os.IInterface {    ... }

      編譯器根據(jù)我們寫的服務接口,重新生成了一個接口,唯一的區(qū)別就是新的接口繼承了IInterface接口。這個接口是干什么的呢?

      public interface IInterface {    public IBinder asBinder(); }

      可以看到,它只有一個接口方法。這個方法用來定義將實現(xiàn)接口的類應該具備返回一個與之相關聯(lián)的Binder的功能,以提供通訊能力。一般實現(xiàn)這個方法的類自己本身就會去繼承Binder。

      這樣的設計使得Binder機制不用關心具體的接口是什么,只要是IInterface就行。事實上相當于是我們在IInterface接口的基礎上擴展了接口功能,本質(zhì)上還是一個IInterface,所以Binder能夠認出它。

      2. 繼承Binder,實現(xiàn)服務接口

      要進行 Binder 通訊,我們自然需要一個 Binder;要實現(xiàn)我們定義的服務接口功能,自然就需要實現(xiàn)服務接口。那么需要滿足這兩個條件怎么辦?很簡單,繼承 Binder,然后實現(xiàn)服務接口就行。

      編譯器為我們生成的類中有一個內(nèi)部類Stub就是這么干的。事實上,這樣的設計隨處可見。你可以看看 CoorChice 這篇文章《3分鐘看懂Activity啟動流程》http://www.jianshu.com/p/9ecea420eb52 中出現(xiàn)的ActivityManagerNative 就是這么干的,雖然它是代理系統(tǒng)的ActivityManagerService,但是模式都是一樣的。

      public static abstract class Stub extends android.os.Binder implements com.coorchice.coorchicelibone.AIDLDemo


      3. Binder需要綁定服務接口,定義DESCRIPTOR描述

      為了一個Binder和一個特定服務接口綁定,以對外提供功能,需要給Binder定義一個DESCRIPTOR描述,表示我這個Binder是提供特定功能鏈接的,不是隨便可以用的。

      通常,DESCRIPTOR描述會直接使用包名 + 服務接口。

      4. 實現(xiàn)asInterface()供客戶端調(diào)用

      作為一個服務提供者,為了能夠給調(diào)用者提供遠程功能,自然需要能夠提供和遠程服務關聯(lián)的 Binder 來通訊,請求服務。獲取 Binder 的接口就是 IInterface 中定義的。

      先查詢一下獲取到的和遠程 Service 通訊的 Binde 中是否已經(jīng)添加了功能接口的實現(xiàn),如果沒有則創(chuàng)建代理,通過代理間接的操作 Binder 和遠程 Service 通訊,實現(xiàn)功能。

      思考:既然我們已經(jīng)獲取到了能夠直接和遠程 Service 通訊的Binder,為什么不直接操作它去向遠程 Service 請求服務呢?

      確實,我們可以直接操作 Binder 向遠程 Service 請求服務,但這過程中有很多繁瑣的操作,還有一些 code碼的區(qū)別,如果不封裝隔離的話,隨著功能的擴展,我們將很難再去維護這段通訊邏輯。還有就是通過這種方式統(tǒng)一的管理通訊邏輯使得它可以隨處使用,而不用沒一個要用的地方都去寫一遍。

      既然是要代理和遠程服務通訊,而且通訊的目的是為了請求服務接口定義的功能,那么很自然就能想到去實現(xiàn)服務接口,然后再對應的接口方法中實現(xiàn)邏輯即可。這樣就可以分開來維護客戶端和服務端的對應的每個功能了。

      所以,我們的代理也需要實現(xiàn)服務接口,然后在代理中操作遠程通訊的Binder進行通訊。

      5. 重寫onTransact()

      在Binder通訊中,一個和遠程端通訊的Binder::transact()方法,會觸發(fā)通訊目標端執(zhí)行Binder::onTransact(),就是說這個時候已經(jīng)收到了通訊發(fā)起端的請求了??纯催@個方法的參數(shù):

      public boolean transact(int code, Parcel data, Parcel reply, int flags){}
      參數(shù)解釋
      code用來標識指令,即這次通訊是使用什么功能。需要客戶端和服務端約定好code碼。
      data來自發(fā)送端的數(shù)據(jù)包。
      reply來自發(fā)送端的接收包,往這個包中寫數(shù)據(jù),就相當于給發(fā)送端返回數(shù)據(jù)。
      flags特殊操作標識。

      對應的我們在看看Binder::transact()方法:

      public boolean transact(int code, Parcel data, Parcel reply, int flags){}
      參數(shù)解釋
      code用來標識指令,即這次通訊是使用什么功能。需要客戶端和服務端約定好code碼。
      data發(fā)送給遠程端的數(shù)據(jù)包。
      reply用于讓遠程端寫回復數(shù)據(jù)的數(shù)據(jù)包
      flags特殊操作標識。

      可以看出來,兩個是成對的操作。Binder::transact()操作是一個阻塞式的操作,就是說在這個方法執(zhí)行返回成功后,直接從reply中讀取的數(shù)據(jù)就是遠程端在Binder::onTransact()中填充的數(shù)據(jù)。

      這個過程可以大概抽象成這個樣子:

      在編譯器自動幫我們生成的onTransact()中,會讀取data中數(shù)據(jù),然后調(diào)用對應的方法(這個方法還沒實現(xiàn),所以我們可以繼承Stub然后重寫,以實現(xiàn)在服務端處理的效果)。比如這個樣子:

      第二步. 創(chuàng)建一個遠程 Service

      我們正常創(chuàng)建一個支持其它應用調(diào)用的 Service,Service  怎么創(chuàng)建就不說。主要看看在 Service 最重要的一步,就是繼承上面生成的Stub,然后自定義一個 Binder。

      接著,在onBinder()中返回一個上面這個Binder的實例給客戶端。

      第三步. 客戶端鏈接Binder

      首先重要的一步是,我們必須把這個aidl文件夾拷貝到客戶端工程的對應目錄下。

      包名不能變!

      包名不能變!

      包名不能變!

      然后通過綁定的方式啟動這個Service。

      總結(jié)

      恭喜你!現(xiàn)在你已經(jīng)掌握AIDL了!

      實際上,從上面的分析可以看出,AIDL其實就是對Binder機制的簡化封裝。Android這一套封裝使得我們在自己定義Service時方便了許多!你可以不用去編寫繁雜的交互,看看編譯器自動生成的文件有多不堪入目吧。

      但是不管怎么封裝,Binder通訊機制的靈魂是不變的,所以要更好的理解這個過程,你可以看看CoorChice的這幾篇文章:

      《從getSystemService()開始,開擼Binder通訊機制》http://www.jianshu.com/p/1050ce12bc1e;

      《能用【白話文】來分析Binder通訊機制?》http://www.jianshu.com/p/fe816777f2cf;

      《Binder機制之一次響應的故事》

      http://www.jianshu.com/p/4fba927dce05

      這幾篇文章從我們接觸最多的上層入手,一步步分析到了 Binder 內(nèi)核層,描述了內(nèi)核的 Bidner 驅(qū)動是如何實現(xiàn)一次完整的 c/s 通訊的。

      與之相關

      從未如此驚艷!你好,SuperTextView

      Android-Material Design風格MVP模式的新聞App(視頻圖片音樂)

      微信號:code-xiaosheng

      公眾號

      「code小生」

        轉(zhuǎn)藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多