Android中使用ContentProvider进行跨进程方法调用
原文同一時候發表在我的博客
點我進入還能看到很多其它
需求背景
近期接到這樣一個需求,須要和別的 App 進行聯動交互,比方下載器 App 和桌面 App 進行聯動。桌面的 App 能直接顯示下載器 App 內的下載任務進度和狀態。
尋找解決方式
從需求上知道了,主要問題在怎樣解決跨進程的通信上邊。
AIDL
AIDL 即 Android Interface Definition Language的縮寫,是專為 Android 中跨進程通信接口的描寫敘述語言。優缺點非常明顯,長處是穩定,快。Android 專門用于跨進程通信設計的。缺點是比較麻煩,AIDL 是通信的約定,參加通信的兩方都須要把這個 AIDL 文件都加入自己的代碼中,然后創建 Service 來實現訪問和被訪問。
ContentProvider
作為 Android 四大基礎組件之中的一個的 ContentProvider 本來它的作用僅僅是提供內容性質的跨進程訪問。可是在 API 11 (Android 3.0) 中,ContentProvider 加入了一個新的方法,能夠用來進行跨進程的方法調用,ContentProvider 中這種方法的定義例如以下:
Bundle call(String method, String arg, Bundle extras)
從易用性來講,這個沒有 AIDL 那么麻煩,并且擴展性更強,也沒有 Broadcast 過于依賴系統,API 11 應該就是主要是缺點了,別的缺點臨時沒發現。歡迎補充。
Broadcast
廣播是最簡單的:長處是把分發消息的任務所有交給 Android 系統了;缺點也是由于全交給系統了,非常多地方不受控制。缺點:
實現
為了簡要,主要講講 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 {@Overridepublic boolean onCreate() {return false;}@Overridepublic Cursor query(Uri uri, String[] strings, String s, String[] strings2, String s2) {return null;}@Overridepublic String getType(Uri uri) {return null;}@Overridepublic Uri insert(Uri uri, ContentValues contentValues) {return null;}@Overridepublic int delete(Uri uri, String s, String[] strings) {return 0;}@Overridepublic int update(Uri uri, ContentValues contentValues, String s, String[] strings) {return 0;}@Overridepublic 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 的 URIprivate 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 {@Overridepublic boolean onCreate() {return false;}@Overridepublic Cursor query(Uri uri, String[] strings, String s, String[] strings2, String s2) {return null;}@Overridepublic String getType(Uri uri) {return null;}@Overridepublic Uri insert(Uri uri, ContentValues contentValues) {return null;}@Overridepublic int delete(Uri uri, String s, String[] strings) {return 0;}@Overridepublic int update(Uri uri, ContentValues contentValues, String s, String[] strings) {return 0;}@Overridepublic Bundle call(String method, String arg, Bundle extras) {// 當被調用“更新狀態”的時候if ("UPDATE_STATUS".equals(method)) {Log.e("Launcher", "update status: " + arg);}return null;}// 我們要調用的對方的 ContentProvider 的 URIprivate 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 的時候須要做一下空指針保護
簽名校驗
總結
以上是生活随笔為你收集整理的Android中使用ContentProvider进行跨进程方法调用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: powerdesigner设置主键为自增
- 下一篇: 发展受阻第一至四季/全集Arrested