主頁 > 移動端開發 > Android Binder,AIDL跨行程通訊詳解與實作,看一遍就懂

Android Binder,AIDL跨行程通訊詳解與實作,看一遍就懂

2021-12-30 10:14:56 移動端開發

1.說到AIDL,就會聯想到Binder機制,

Binder 是一種行程間通信機制
整個app屬于客戶端,系統是服務端,他們之間的通訊就是通過IPC互動,中間服務就是serviceSystem
優點:性能,穩定性,安全性
設計:Client/Server/ServiceManager/驅動
實作:AIDL

二、核心代碼處

1.可以通過AndroidStudio創建:

1.1選中一個包進行新建一個aidl,系統會自動生成一個aidl的檔案夾

1.2手動創建檔案夾,創建包名,然后在包內創建aidl檔案,

1.3我們創建兩個AIDL檔案 IMsgManager.aidl,IReceiverMsgListener

IMsgManager:訊息管理類,提供訊息的介面

IReceiverMsgListener:訊息接收類,做轉發使用

1.4Msg是物件,aidl常見的引數只支持簡單的資料型別,物件需要通過Parcelable序列化處理

1.4.1 先定義一個Msg 實作 Parcelable介面,,注意這個類的包名一定要與aidl檔案下的包名一致,因為我們要定義一個空的Msg.aidl檔案,這樣Msg.aidl檔案才會與Msg.Java檔案關聯起來

Msg.aidl檔案:洗掉interface Msg,將Msg申明為 parcelable;

這樣就就可以了,

IMsgManager:

由于aidl檔案不能關聯,使用類都需要手動匯入包名,

IReceiveMsgListener:

定義好AIDL檔案,我們要生成對應的java檔案:點擊

將專案編譯一下,aidl檔案對應的java檔案出現在這個下方,

這個時候有人會發現少了一個Msg的java檔案,由于我們將Msg.aidl申明為 parcelable,將會關聯Parcelable的物體,和java檔案已關聯起來,

這樣,我們就可以通過aidl發送自定義物件,

2.Service的處理(C/S)

2.1我們需要創建一個Service ,作為服務端在監控

public class MySevice extends Service {
    //AIDL不支持正常的介面回呼,使用RemoteCallbackList實作介面回呼
    private RemoteCallbackList<IReceiveMsgListener> mReceiveListener = new RemoteCallbackList<IReceiveMsgListener>();


    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return new MyIBinder();
    }



    public class MyIBinder extends IMsgManager.Stub {

        @Override
        public void sendMsg(Msg msg) throws RemoteException {
            receiveMsg(msg);
        }

        @Override
        public void registerReceiveListener(IReceiveMsgListener receiveListener) throws RemoteException {
            mReceiveListener.register(receiveListener);
        }

        @Override
        public void unregisterReceiveListener(IReceiveMsgListener receiveListener) throws RemoteException {
            boolean success = mReceiveListener.unregister(receiveListener);
            if (success){
                Log.d("tag","===  解除注冊成功");
            }else {
                Log.d("tag","===  解除注冊失敗 ");
            }

        }

        @Override
        public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
            return super.onTransact(code, data, reply, flags);
        }
    };

    //收到訊息處理
    public void receiveMsg(Msg msg) {
        //通知Callback回圈開始,回傳size為實作mReceiveListener回呼的個數
        final int size = mReceiveListener.beginBroadcast();
        msg.setMsg("我是服務器,我收到了:"+msg.getMsg());
        for (int i = 0; i < size; i++){
            IReceiveMsgListener listener = mReceiveListener.getBroadcastItem(i);
            if (listener != null){
                try {
                    listener.onReceive(msg);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        }
        //通知通知Callback回圈結束
        mReceiveListener.finishBroadcast();
    }



}

2.2將service注冊到AndroidManifest

<service
    android:name="com.example.mydemo.service.MySevice"
    android:process=":remote"//同一應用內跨行程通信需
    android:enabled="true"
    android:exported="true" //暴露
    >

    <intent-filter>
        <action android:name="com.test.aidl.action"/>
    </intent-filter>

</service>

三、Service與Activity之間的通訊(在當前APP內)

3.1系結服務

IMsgManager myIBinder = null;
private TextView textView;
private Button button_1, button_2, button_3;
public static final String ACTIO_SERVICE = "com.test.aidl.action";
IMsgManager iMsgManager;
private EditText  editText_1;

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

}

private void initView() {
    editText_1=findViewById(R.id.edit_1);
    textView = findViewById(R.id.text_1);
    button_1 = findViewById(R.id.btn_1);
    button_2 = findViewById(R.id.btn_2);
    button_3 = findViewById(R.id.btn_3);

    button_1.setOnClickListener(this);
    button_2.setOnClickListener(this);
    button_3.setOnClickListener(this);

}


@Override
public void onClick(View v) {

    if (v == button_1) {
        //系結
        bindService();

    } else if (v == button_2) {
        //發送
        try {
            if (myIBinder != null) {
                if (editText_1.getText().toString().isEmpty())
                    return;
                Msg msg = new Msg("服務端發送:"+editText_1.getText());
                myIBinder.sendMsg(msg);
            }
        } catch (RemoteException e) {
            e.printStackTrace();
        }

    } else if (v == button_3) {
        //解綁
        unbindService(connection);

    }

}


private void bindService() {
        //注冊service
    Intent intent = new Intent(this, MySevice.class);
    intent.setAction(ACTIO_SERVICE);
    bindService(intent, connection, Service.BIND_AUTO_CREATE);

}


//service的鏈接
private ServiceConnection connection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        myIBinder = IMsgManager.Stub.asInterface(service);
        iMsgManager = IMsgManager.Stub.asInterface(service);
        try {
            //注冊binder連接
            iMsgManager.asBinder().linkToDeath(mDeathRecipient, 0);
        } catch (RemoteException e) {
            e.printStackTrace();
        }

        try {
            iMsgManager.registerReceiveListener(mReceiveMsgListener);
        } catch (RemoteException e) {
            e.printStackTrace();
        }

    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        //斷開連接

    }
};




private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
    // //當承載IBinder的行程消失時接識訓呼的介面
    @Override
    public void binderDied() {
        if (null == iMsgManager) {
            return;
        }
        //解綁
        iMsgManager.asBinder().unlinkToDeath(mDeathRecipient, 0);
        iMsgManager = null;
    }
};

private IReceiveMsgListener mReceiveMsgListener = new IReceiveMsgListener.Stub() {

    @Override
    public void onReceive(Msg msg) throws RemoteException {
             //訊息分發
        textView.append("\n" + msg.getMsg());


    }
};

這樣就完成再App的訊息分發

四、我們要在兩個App中實作訊息傳遞,也就是跨行程IPC,

由于我們已完成了一個service端的開發,我們在創建一個新的app,作為令一個行程,

4.1同樣把所service APP中的aidl復制到B的app中,Msg物件也要一同復制到對應的包下(兩邊保持一致)

把Msg自定義的物體也復制過來,兩邊要保持包名一致,接下我們還是需要make一下專案,

執行完,會生成一下

4.2 實作service的系結,可以把A app的代碼復制過來,修改注冊service方法

IMsgManager myIBinder = null;
private TextView textView;
private Button button_1, button_2, button_3;
public static final String ACTIO_SERVICE = "com.test.aidl.action";
IMsgManager iMsgManager;
EditText edit_1;

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

}

private void initView() {
    edit_1=findViewById(R.id.edit_1);
    textView = findViewById(R.id.text_1);
    button_1 = findViewById(R.id.btn_1);
    button_2 = findViewById(R.id.btn_2);
    button_3 = findViewById(R.id.btn_3);

    button_1.setOnClickListener(this);
    button_2.setOnClickListener(this);
    button_3.setOnClickListener(this);

}


@Override
public void onClick(View v) {

    if (v == button_1) {
        //系結
        bindService();

    } else if (v == button_2) {
        //接收
        try {
            if (myIBinder != null) {
                if (edit_1.getText().toString().isEmpty())
                    return;
                Msg msg = new Msg("客戶端發送:"+edit_1.getText());
                myIBinder.sendMsg(msg);
            }
        } catch (RemoteException e) {
            e.printStackTrace();
        }

    } else if (v == button_3) {
        //解綁
        unbindService(connection);

    }

}


private void bindService() {
//系結需要注意一下,由于我們啟動其他應用的,需要知道包名和,filter-action
    Intent intent = new Intent();
    intent.setPackage("com.example.mydemoa");//包名,服務端的包名(service)
    intent.setAction(ACTIO_SERVICE);//action
    bindService(intent, connection, Service.BIND_AUTO_CREATE);

}


private ServiceConnection connection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        myIBinder = IMsgManager.Stub.asInterface(service);
        iMsgManager = IMsgManager.Stub.asInterface(service);
        try {
            iMsgManager.asBinder().linkToDeath(mDeathRecipient, 0);
        } catch (RemoteException e) {
            e.printStackTrace();
        }

        try {
            iMsgManager.registerReceiveListener(mReceiveMsgListener);
        } catch (RemoteException e) {
            e.printStackTrace();
        }

    }

    @Override
    public void onServiceDisconnected(ComponentName name) {

    }
};


private void showUI() throws RemoteException {

}


private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
    // //當承載IBinder的行程消失時接識訓呼的介面
    @Override
    public void binderDied() {
        if (null == iMsgManager) {
            return;
        }
        iMsgManager.asBinder().unlinkToDeath(mDeathRecipient, 0);
        iMsgManager = null;
    }
};

private IReceiveMsgListener mReceiveMsgListener = new IReceiveMsgListener.Stub() {

    @Override
    public void onReceive(Msg msg) throws RemoteException {
        msg.setTime(System.currentTimeMillis());
        textView.append("\n" + msg.getMsg());


    }
};

4.4這樣基本完成,接下來開始測驗,測驗先啟動service的app,然后在打開b的,否則B打開,service沒有啟動,導致訊息無法傳遞

五、結果:

這樣就完成了跨行程訊息傳遞

注意:關于自定義物件,是先創建一個物體物件,實作Parcelable介面,再在aidl檔案夾下的包內創建一個aidl檔案名為java一樣的,同事包名也一樣,洗掉aidl檔案內介面代碼行,

interface Msg{
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */

}

然后改成申明為:parcelable Msg;即可,不然會報錯,網上大多數教程都沒有交會如何關聯自定義java檔案與aidl檔案,

*************************************************************************************************************

很感謝官方,今天剛整理好,就推上了領域內容熱榜第八名,以后將會寫出更好的博客回饋大家,

轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/397400.html

標籤:其他

上一篇:安卓應用hook測驗

下一篇:iOS底層 - 符號決議(dSYM & 系統符號)Go語言版本

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【從零開始擼一個App】Dagger2

    Dagger2是一個IOC框架,一般用于Android平臺,第一次接觸的朋友,一定會被搞得暈頭轉向。它延續了Java平臺Spring框架代碼碎片化,注解滿天飛的傳統。嘗試將各處代碼片段串聯起來,理清思緒,真不是件容易的事。更不用說還有各版本細微的差別。 與Spring不同的是,Spring是通過反射 ......

    uj5u.com 2020-09-10 06:57:59 more
  • Flutter Weekly Issue 66

    新聞 Flutter 季度調研結果分享 教程 Flutter+FaaS一體化任務編排的思考與設計 詳解Dart中如何通過注解生成代碼 GitHub 用對了嗎?Flutter 團隊分享如何管理大型開源專案 插件 flutter-bubble-tab-indicator A Flutter librar ......

    uj5u.com 2020-09-10 06:58:52 more
  • Proguard 常用規則

    介紹 Proguard 入口,如何查看輸出,如何使用 keep 設定入口以及使用實體,如何配置壓縮,混淆,校驗等規則。

    ......

    uj5u.com 2020-09-10 06:59:00 more
  • Android 開發技術周報 Issue#292

    新聞 Android即將獲得類AirDrop功能:可向附近設備快速分享檔案 谷歌為安卓檔案管理應用引入可安全隱藏資料的Safe Folder功能 Android TV新主界面將顯示電影、電視節目和應用推薦內容 泄露的Android檔案暗示了傳說中的谷歌Pixel 5a與折疊屏新機 谷歌發布Andro ......

    uj5u.com 2020-09-10 07:00:37 more
  • AutoFitTextureView Error inflating class

    報錯: Binary XML file line #0: Binary XML file line #0: Error inflating class xxx.AutoFitTextureView 解決: <com.example.testy2.AutoFitTextureView android: ......

    uj5u.com 2020-09-10 07:00:41 more
  • 根據Uri,Cursor沒有獲取到對應的屬性

    Android: 背景:呼叫攝像頭,拍攝視頻,指定保存的地址,但是回傳的Cursor檔案,只有名稱和大小的屬性,沒有其他諸如時長,連ID屬性都沒有 使用 cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATIO ......

    uj5u.com 2020-09-10 07:00:44 more
  • Android連載29-持久化技術

    一、持久化技術 我們平時所使用的APP產生的資料,在記憶體中都是瞬時的,會隨著斷電、關機等丟失資料,因此android系統采用了持久化技術,用于存盤這些“瞬時”資料 持久化技術包括:檔案存盤、SharedPreference存盤以及資料庫存盤,還有更復雜的SD卡記憶體儲。 二、檔案存盤 最基本存盤方式, ......

    uj5u.com 2020-09-10 07:00:47 more
  • Android Camera2Video整合到自己專案里

    背景: Android專案里呼叫攝像頭拍攝視頻,原本使用的 MediaStore.ACTION_VIDEO_CAPTURE, 后來因專案需要,改成了camera2 1.Camera2Video 官方demo有點問題,下載后,不能直接整合到專案 問題1.多次拍攝視頻崩潰 問題2.雙擊record按鈕, ......

    uj5u.com 2020-09-10 07:00:50 more
  • Android 開發技術周報 Issue#293

    新聞 谷歌為Android TV開發者提供多種新功能 Android 11將自動填表功能整合到鍵盤輸入建議中 谷歌宣布Android Auto即將支持更多的導航和數字停車應用 谷歌Pixel 5只有XL版本 搭載驍龍765G且將比Pixel 4更便宜 [圖]Wear OS將迎來重磅更新:應用啟動時間 ......

    uj5u.com 2020-09-10 07:01:38 more
  • 海豚星空掃碼投屏 Android 接收端 SDK 集成 六步驟

    掃碼投屏,開放網路,獨占設備,不需要額外下載軟體,微信掃碼,發現設備。支持標準DLNA協議,支持倍速播放。視頻,音頻,圖片投屏。好點意思。還支持自定義基于 DLNA 擴展的操作動作。好像要收費,沒體驗。 這里簡單記錄一下集成程序。 一 跟目錄的build.gradle添加私有mevan倉庫 mave ......

    uj5u.com 2020-09-10 07:01:43 more
最新发布
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:40:31 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:40:11 more
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:39:36 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:39:13 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:16:23 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:16:15 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:15:46 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:14:53 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:14:08 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:08:34 more