android:使用Messenger進行進程間通信(一)

来源:http://www.cnblogs.com/happyhacking/archive/2016/03/25/5318418.html
-Advertisement-
Play Games

Messenger簡介 Messenger和AIDL是實現進程間通信(interprocess communication)的兩種方式. 實際上,Messenger的實現其實是對AIDL的封裝. Messenger適合於多進程單線程,AIDL適合於多進程多線程,需要開發者自己實現線程安全. goog ...


Messenger簡介

Messenger和AIDL是實現進程間通信(interprocess communication)的兩種方式.
實際上,Messenger的實現其實是對AIDL的封裝.
Messenger適合於多進程單線程,AIDL適合於多進程多線程,需要開發者自己實現線程安全.
google官方文檔指出對於大部分的程式,service不需要執行多線程,所以應該首先考慮使用Messenger.

為什麼需要進程間通信?

因為不同進程之間的數據是不共用的.

實踐(以音樂播放器demo為例)

關鍵詞: bind + messenger + handler

step1 (AndroidManifest.xml)在AndroidManifest.xml中註冊service,並設置為其android:process屬性賦值

註意① 忘記註冊service的話,程式不會響應,但是也不會崩潰的...
註意② 此處設置該service為一個全局進程,意即不同應用程式可以共用該進程,若process以":"開頭,則表示其為該應用程式的私有進程.

        <service android:name=".MusicService"
            android:process="com.example.janiszhang.musicplayer.service.process"/>

step2 (MusicService)在service中實現一個繼承Handler的子類(),用於處理由activity發來的message

 class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            mActivityMessenger = msg.replyTo;
            switch (msg.what) {
                case 0:
                    mMediaPlayer.stop();
                    i  = msg.arg1;
                    mMediaPlayer = MediaPlayer.create(MusicService.this, mMusicDatas.get(i).getSrc());
                    if(isPlaying) {
                        mMediaPlayer.start();
                    }
                    //mRemoteViews.setTextViewText(R.id.music_name, mMusicDatas.get(i).getName());
                    //mRemoteViews.setTextViewText(R.id.singer_name, mMusicDatas.get(i).getSinger());
                    //mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
                    break;
                case 1:
                    if(msg.arg1==1){
                        isPlaying =false;
                        mMediaPlayer.pause();
                        //mRemoteViews.setImageViewResource(R.id.btn_play, R.drawable.note_btn_play);
                        //mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
                    } else {
                        isPlaying = true;
                        i = msg.arg2;
                        mMediaPlayer = MediaPlayer.create(MusicService.this, mMusicDatas.get(i).getSrc());
                        mMediaPlayer.start();
                        //mRemoteViews.setImageViewResource(R.id.btn_play, R.drawable.note_btn_pause);
                        //mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
                    }
                    break;
                default:
                    break;
            }
        }
    }

step3 (MusicService)實例化自定義的handler,作為參數,創建一個Messenger

    Messenger mMessenger = new Messenger(new IncomingHandler());

step4 (MusicService)實現onBind()方法

   @Nullable
    @Override
    public IBinder onBind(Intent intent) {

        return mMessenger.getBinder();
    }

step5 (MusicActivity) 創建一個ServiceConnection實例,在onServiceConnected方法中獲取到service返回的messenger.

 private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {

            mMessenger = new Messenger(service);

        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

step6 (MusicActivity)bindservice

        Intent intent = new Intent(this, MusicService.class);
        bindService(intent, mServiceConnection, BIND_AUTO_CREATE);

step7 bind成功後,就可以獲取到一個Messenger的實例,通過該實例activity可以向另外一個進程中的service發送message,例如:

mNextBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mIndex = (mIndex+1)>=mMusicDatas.size()? 0 : mIndex+1;
                setMusicNameAndSingerName(mIndex);
                if(mMessenger != null) {
                    Message message = Message.obtain(null, 0);
                    message.arg1 = mIndex;
                    message.replyTo = mActivityMessenger;
                    try {
                        mMessenger.send(message);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }
            }
        });

至此,基於Messenger的由activity到service的進程間通信就是實現完成了.

遇到的問題:

當我試圖Message實例的obj賦值為true時,會導致異常:

java.lang.RuntimeException: Can't marshal non-Parcelable objects across processes.

意思是說obj應該是一個實現了Parcelable介面的對象.

解決方案:對於這種情況,應該使用bundle來傳遞數據.

總結一下:
1.activity與service以bind的方式通信.
2.service中創建一個用於處理數據的handler,並以之為參數創建一個Messenger,通過onbind返回給activity.
3.activity使用service返回的Messenger實例send message

github地址:https://github.com/zhangbz/MusicPlayer


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 什麼是主線程? 一個iOS程式運行後,預設會開啟一條線程,稱為“主線程”或“UI線程” 主線程的主要作用 1.顯示/刷新UI界面 2.處理UI事件(比如點擊事件,滾動事件,拖拽事件) 主線程的使用註意 1.別將比較耗時的操作放在主線程中 2.耗時操作會卡在主線程中,嚴重影響UI的流暢程度 如圖,將耗 ...
  • DrawerLayout是V4包下提供的一種左滑右滑抽屜佈局效果。 實現效果如下: 因為是官方提供的,所以使用起來也相對的比較簡單。 DrawerLayout 提供 1、當界面彈出的時候,主要內容區會自動背景變黑,當點擊內容區的時候,抽屜佈局會消失 2、在屏幕邊緣手勢滑動 會拉出抽屜佈局 註意:當按 ...
  • 圖片輪播是一種常見的自定義控制項,也有多種實現的方法,這裡提供一種簡單的ViewPager實現的案例。 實現功能:圖片迴圈輪播,進度顯示,圖片點擊事件 實現只需三步: 1 添加類文件到項目中。 2 在xml佈局中引入標簽。 3 實例化並設置簡單參數。 具體使用方法,詳見代碼註釋。 ==========... ...
  • 1.先來看看效果,這裡做了三個功能 2.實現app之間的跳轉需要註意兩方面 3首先來講url和白名單的設置 4.實現跳轉的代碼 5.demo:https://github.com/TigerCui/MyAppJumpToYourApp.git ...
  • 在學習多線程之前需要瞭解什麼是進程? 進程是指在系統中正在運行的一個應用程式 每個進程之間是獨立的,每個進程均運行在其專用且受保護的記憶體空間內 可以通過“活動監視器”查看Mac中所開啟的進程 下一個問題什麼是線程? 一個進程想要執行任務,必須得有線程(每一個進程只收要有一個主線程) 一個進程中的所有 ...
  • 什麼是讀寫鎖 讀寫鎖是多線程下的一種同步機制, 它還有很多其他的名字,比如共用 獨占鎖等等。被它保護的資源有以下幾種狀態: 初始狀態 沒有線程訪問資源時所在的狀態 共用狀態 有多個讀線程訪問資源時進入共用狀態,這個時候允許新的讀線程訪問資源,但是寫線程必須等待 獨占狀態 寫線程訪問資源時進入獨占狀態 ...
  • 該篇文章是我自己從我的新浪博客上摘抄過來的, 原文鏈接為: http://blog.sina.com.cn/s/blog_dcc636350102wat5.html 在iOS開發中, 難免會集成別人的三方類庫, 當集成的三方類庫過多時, 難免會出現某些庫同時使用了同樣的函數庫,導致link的時候報錯 ...
  • 因為Pthread很少用到,所以對於Pthread的知識沒有摳那麼細緻,所以將Pthread和 NSThread放在了一起。 4.1 Pthread 4.1-1.0 創建線程 - pthread_create 4.1-1.1 __bridge 橋接 <!--?xml version="1.0" en ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...