博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android中使用ContentProvider进行跨进程方法调用
阅读量:6320 次
发布时间:2019-06-22

本文共 4699 字,大约阅读时间需要 15 分钟。

原文同一时候发表在我的博客

需求背景

近期接到这样一个需求。须要和别的 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 的定义:

我特地加了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 的定义:

然后在桌面 App 中,就能够通过 LauncherContentProvider 的 download 方法和 pause 方法来调用下载器 App 的功能了(这两个方法写在这里不太合适。只是我仅仅是为了节省篇幅放一起了)。

下载器 App 中被调用了方法。就会调用桌面 App 的更新状态。

这里仅仅是演示了一个交互的过程。有很多其它问题欢迎大家一起讨论学习~~

引申

  • 找不到 ContentProvider 的时候须要做一下空指针保护

  • 签名校验

转载于:https://www.cnblogs.com/gavanwanggw/p/7001929.html

你可能感兴趣的文章
配置和概况
查看>>
非唯一列上的非聚集索引
查看>>
Google glog 使用
查看>>
React与ES6(四)ES6如何处理React mixins
查看>>
MySQL5.6忘记root密码(win平台)
查看>>
信鬼神 信风水 信命运 皆因无力及妄念所致
查看>>
【开源】知乎日报UWP 更新
查看>>
浅谈C# 中的lock 方法与Monitor 类的关系_以及同步与互斥
查看>>
仿Google首页搜索自动补全!(原创分享jQuery版)
查看>>
tkinter的GUI设计:界面与逻辑分离(三)-- 多页面
查看>>
CHM 打开时提示 已取消到该网页的导航
查看>>
软件(代码)开源,协议声明
查看>>
java web开发人员经常使用标签
查看>>
修改linux的最大文件句柄数限制
查看>>
基于zepto的移动端日期+时间选择插件
查看>>
JDK5.0新特性系列---11.1线程 Callable和Future
查看>>
QTP的那些事--VBS函数大全
查看>>
爆牙齿的世界杯日记(小组次轮)
查看>>
09.移动先行之谁主沉浮----控件之轮流轰炸——高级控件
查看>>
Hibernate 缓存机制浅析
查看>>