Android中使用ContentProvider進行跨進程方法調用

來源:互聯網
上載者:User

標籤:android   跨進程   

原文同時發表在我的部落格
點我進入還能看到更多

需求背景

最近接到這樣一個需求,需要和別的 App 進行聯動互動,比如下載器 App 和案頭 App 進行聯動,案頭的 App 能直接顯示下載器 App 內的下載任務進度和狀態。

尋找解決方案

從需求上知道了,主要問題在如何解決跨進程的通訊上邊。

  1. AIDL

    AIDL 即 Android Interface Definition Language的縮寫,是專為 Android 中跨進程通訊介面的描述語言。優缺點很明顯,優點是穩定,快,Android 專門用於跨進程通訊設計的。缺點是比較麻煩,AIDL 是通訊的約定,參加通訊的雙方都需要把這個 AIDL 檔案都加入自己的代碼中,然後建立 Service 來實現訪問和被訪問。

  2. ContentProvider

    作為 Android 四大基礎組件之一的 ContentProvider 本來它的作用只是提供內容性質的跨進程訪問。但是在 API 11 (Android 3.0) 中,ContentProvider 加入了一個新的方法,可以用來進行跨進程的方法調用,ContentProvider 中這個方法的定義如下:

    Bundle call(String method, String arg, Bundle extras)

    從易用性來講,這個沒有 AIDL 那麼麻煩,而且擴充性更強,也沒有 Broadcast 過於依賴系統,API 11 應該就是主要是缺點了,別的缺點暫時沒發現,歡迎補充。

  3. Broadcast

    廣播是最簡單的:優點是把分發訊息的任務全部交給 Android 系統了;缺點也是因為全交給系統了,很多地方不受控制。缺點:

    1. 雖然廣播可以通過指定包名來進行發送指向性訊息,但是卻不能驗證訊息去向 App 的簽名。
    2. 系統重啟之後,在系統的廣播隊列裡邊的訊息就丟失了。
實現

為了簡要,主要講講 ContentProvider 吧。

ContentProvider

首先是下載器 App 的 ContentProvider 代碼實現

package cn.hiroz.downloader.realname;import android.content.ContentProvider;import android.content.ContentValues;import android.database.Cursor;import android.net.Uri;import android.os.Binder;import android.os.Bundle;import android.util.Log;public class DownloaderContentProvider extends ContentProvider {    @Override    public boolean onCreate() {        return false;    }    @Override    public Cursor query(Uri uri, String[] strings, String s, String[] strings2, String s2) {        return null;    }    @Override    public String getType(Uri uri) {        return null;    }    @Override    public Uri insert(Uri uri, ContentValues contentValues) {        return null;    }    @Override    public int delete(Uri uri, String s, String[] strings) {        return 0;    }    @Override    public int update(Uri uri, ContentValues contentValues, String s, String[] strings) {        return 0;    }    @Override    public Bundle call(String method, String arg, Bundle extras) {        if ("DOWNLOAD".equals(method)) {     // 當調用我下載的時候            Log.e("Downloader", "download: " + arg);            // 調用案頭 App 的方法來更新狀態            updateStatus("download");        } else ("PAUSE".equals(method)) {    // 當調用我暫停時候            Log.e("Downloader", "pause: " + arg);            // 調用案頭 App 的方法來更新狀態            updateStatus("pause");        }        return null;    }    // 我們要調用的對方的 ContentProvider 的 URI    private final Uri LAUNCHERCONTENTPROVIDER_URI = Uri.parse("content://cn.hiroz.launcher.LauncherContentProvider");}    private void updateStatus(String status) {        getContext().getContentResolver().call(LAUNCHERCONTENTPROVIDER_URI, "UPDATE_STATUS", status, new Bundle());    }

在下載器 App 的 AndroidManifest.xml 中還需要添加 ContentProvider 的定義:

<provider    android:name="cn.hiroz.downloader.realname.DownloaderContentProvider"    android:authorities="cn.hiroz.downloader.DownloaderContentProvider"    android:exported="true"/>

我特地加了authorities設定,這樣在互動時候訪問的 ContentProvider 的 URI 會看起來不一樣,也不會暴露我真實的 ContentProvider 類

然後是案頭 App 的 ContentProvider 代碼實現

package cn.hiroz.launcher.realname;import android.content.ContentProvider;import android.content.ContentValues;import android.database.Cursor;import android.net.Uri;import android.os.Binder;import android.os.Bundle;import android.util.Log;public class LauncherContentProvider extends ContentProvider {    @Override    public boolean onCreate() {        return false;    }    @Override    public Cursor query(Uri uri, String[] strings, String s, String[] strings2, String s2) {        return null;    }    @Override    public String getType(Uri uri) {        return null;    }    @Override    public Uri insert(Uri uri, ContentValues contentValues) {        return null;    }    @Override    public int delete(Uri uri, String s, String[] strings) {        return 0;    }    @Override    public int update(Uri uri, ContentValues contentValues, String s, String[] strings) {        return 0;    }    @Override    public Bundle call(String method, String arg, Bundle extras) {        // 當被調用“更新狀態”的時候        if ("UPDATE_STATUS".equals(method)) {            Log.e("Launcher", "update status: " + arg);        }        return null;    }    // 我們要調用的對方的 ContentProvider 的 URI    private final Uri DOWNLOADERCONTENTPROVIDER_URI = Uri.parse("content://cn.hiroz.downloader.DownloaderContentProvider");}    public void download(String arg) {        getContext().getContentResolver().call(DOWNLOADERCONTENTPROVIDER_URI, "DOWNLOAD", status, new Bundle());    }    public void pause(String arg) {        getContext().getContentResolver().call(DOWNLOADERCONTENTPROVIDER_URI, "PAUSE", status, new Bundle());    }}

在案頭 App 的 AndroidManifest.xml 中還需要添加 ContentProvider 的定義:

<provider    android:name="cn.hiroz.launcher.realname.LauncherContentProvider"    android:authorities="cn.hiroz.launcher.LauncherContentProvider"    android:exported="true"/>

然後在案頭 App 中,就可以通過 LauncherContentProvider 的 download 方法和 pause 方法來調用下載器 App 的功能了(這兩個方法寫在這裡不太合適,不過我僅僅是為了節省篇幅放一起了)。下載器 App 中被調用了方法,就會調用案頭 App 的更新狀態。

這裡只是示範了一個互動的過程,有更多問題歡迎大家一起討論學習~~

引申
  • 找不到 ContentProvider 的時候需要做一下null 指標保護

  • 簽名校正

Android中使用ContentProvider進行跨進程方法調用

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.