android 跨进程接收广播,Android ContentProvider跨进程通信方案

一、为什么使用ContentProvider跨进程通信?

Android中跨进程通信的方式很多,除了共享内存(无法隔离进程)、UnixSocket(多次拷贝)、管道(多次拷贝,队列效率低),最常用的就是Binder了。其中Binder最简单的是发送广播就能跨进程通信,接着是常用的Service(Android 推荐的BindService)。作为使用Binder通信的ContentProvider ,相比有什么优势?

1、广播

广播是最简单的:优点是把分发消息的任务全部交给 Android 系统了;缺点也是因为全交给系统了,很多地方不受控制。缺点:

虽然广播可以通过指定包名来进行发送指向性消息,但是却不能验证消息去向 App 的签名。

系统重启之后,在系统的广播队列里边的消息就丢失了

2、Service+AIDL

AIDL 即 Android Interface Definition Language的缩写,是专为 Android 中跨进程通信接口的描述语言。

优缺点很明显,

优点是:

稳定,快,Android 专门用于跨进程通信设计的。

缺点是:

比较麻烦,AIDL 是通信的约定,参加通信的双方都需要把这个 AIDL 文件都加入自己的代码中,然后创建 Service

来实现访问和被访问。

容易出现连接断开或者DeadObjectException,从而某些情况下容易造成数据丢失

Service题外话

此外,官方推荐使用bindService,这种方式编码时总有很多不便,实际上不通过bindservice也可以访问aidl,具体参考 《Android Parcel实现反向Binder通信》,Service+AIDL 既然也可以通过不绑定方式就能跨进程通信?为什么还有使用ContentProvider呢,因为不通过binderService就需要通过startService+Intent,在Intent中将binder 传递过来,但这种方式在android 8.0之后无法在后台startService,否则必须启动前台Service,前台Service影响用户体验。

3、ContentProvider

作为 Android 四大基础组件之一的 ContentProvider 本来它的作用只是提供内容性质的跨进程访问。但是在 API 11 (Android 3.0) 中,ContentProvider 加入了一个新的方法,可以用来进行跨进程的方法调用,ContentProvider 中这个方法的定义如下:

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

优点:

1、由AMS直接管理,可靠性高于AIDL+Service

2、支持binder线程池,可避免主线程ANR问题

3、数据传输可靠性高,极大避免连接断开和DeadObject问题

4、OnCreate方法早于Application OnCreate调用,初始化优势明显

5、支持同步调用,支持回调

缺点:

不支持Android 11之前的版本

AMS 对Manifest中的ContentProvider会进行组件检查,如果ContentProvider不存在会出现crash,当然可以通过Proxy方式避免。

二、使用方法

1、同步调用

server端:

package com.smartian.rpc.provider;

public class ServerContentProvider extends ContentProvider {

public final static String SERVER_PROVIDER_AUTHORITIES = "com.smartian.rpc.provider.ServerContentProvider";

public final static String SERVER_PROVIDER_SCHEME = "content://";

private static final String TAG = "ServerProvider";

@Override

public boolean onCreate() {

return false;

}

@Nullable

@Override

public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {

return null;

}

@Nullable

@Override

public String getType(@NonNull Uri uri) {

return null;

}

@Nullable

@Override

public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {

return null;

}

@Override

public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {

return 0;

}

@Override

public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {

return 0;

}

@Nullable

@Override

public Bundle call(@NonNull String method, @Nullable String arg, @Nullable Bundle extras) {

String result = "call : "+method+", arg: "+arg+" , bundle: "+extras.getString("index") +", 线程id:"+Thread.currentThread().getName();

Bundle b = new Bundle();

b.putString("result",result);

return b;

}

}

client端:

ContentResolver cr = getApplicationContext().getContentResolver();

ArrayList list = new ArrayList<>();

for (int i=0;i<100;i++){

Bundle b = new Bundle();

list.add(""+i);

b.putString("index",""+i);

Uri uri = Uri.parse(ServerContentProvider.SERVER_PROVIDER_SCHEME+ ServerContentProvider.SERVER_PROVIDER_AUTHORITIES);

Bundle resultBundle = cr.call(uri,"hello","id="+(i+1),b);

Log.d("Client","result: " + resultBundle.getString("result"));

}

清单文件

android:authorities="com.smartian.rpc.provider.ServerContentProvider"

android:name="com.smartian.rpc.provider.ServerContentProvider"

android:exported="true"

android:process=":service_provider"

>

执行结果

result: call : hello, arg: id=1 , bundle: 0, 线程id:Binder:1686_3

2020-09-27 12:12:17.307 1538-1538/? D/Client: result: call : hello, arg: id=2 , bundle: 1, 线程id:Binder:1686_1

2020-09-27 12:12:17.310 1538-1538/? D/Client: result: call : hello, arg: id=3 , bundle: 2, 线程id:Binder:1686_2

2020-09-27 12:12:17.313 1538-1538/? D/Client: result: call : hello, arg: id=4 , bundle: 3, 线程id:Binder:1686_3

2020-09-27 12:12:17.316 1538-1538/? D/Client: result: call : hello, arg: id=5 , bundle: 4, 线程id:Binder:1686_3

2020-09-27 12:12:17.318 1538-1538/? D/Client: result: call : hello, arg: id=6 , bundle: 5, 线程id:Binder:1686_3

2020-09-27 12:12:17.321 1538-1538/? D/Client: result: call : hello, arg: id=7 , bundle: 6, 线程id:Binder:1686_3

2020-09-27 12:12:17.323 1538-1538/? D/Client: result: call : hello, arg: id=8 , bundle: 7, 线程id:Binder:1686_3

2020-09-27 12:12:17.326 1538-1538/? D/Client: result: call : hello, arg: id=9 , bundle: 8, 线程id:Binder:1686_3

2020-09-27 12:12:17.329 1538-1538/? D/Client: result: call : hello, arg: id=10 , bundle: 9, 线程id:Binder:1686_3

2020-09-27 12:12:17.332 1538-1538/? D/Client: result: call : hello, arg: id=11 , bundle: 10, 线程id:Binder:1686_3

2020-09-27 12:12:17.334 1538-1538/? D/Client: result: call : hello, arg: id=12 , bundle: 11, 线程id:Binder:1686_3

2020-09-27 12:12:17.337 1538-1538/? D/Client: result: call : hello, arg: id=13 , bundle: 12, 线程id:Binder:1686_3

2020-09-27 12:12:17.340 1538-1538/? D/Client: result: call : hello, arg: id=14 , bundle: 13, 线程id:Binder:1686_3

2020-09-27 12:12:17.342 1538-1538/? D/Client: result: call : hello, arg: id=15 , bundle: 14, 线程id:Binder:1686_3

2020-09-27 12:12:17.345 1538-1538/? D/Client: result: call : hello, arg: id=16 , bundle: 15, 线程id:Binder:1686_3

2020-09-27 12:12:17.348 1538-1538/? D/Client: result: call : hello, arg: id=17 , bundle: 16, 线程id:Binder:1686_3

2020-09-27 12:12:17.351 1538-1538/? D/Client: result: call : hello, arg: id=18 , bundle: 17, 线程id:Binder:1686_3

2020-09-27 12:12:17.354 1538-1538/? D/Client: result: call : hello, arg: id=19 , bundle: 18, 线程id:Binder:1686_3

2020-09-27 12:12:17.357 1538-1538/? D/Client: result: call : hello, arg: id=20 , bundle: 19, 线程id:Binder:1686_3

2020-09-27 12:12:17.359 1538-1538/? D/Client: result: call : hello, arg: id=21 , bundle: 20, 线程id:Binder:1686_3

2020-09-27 12:12:17.362 1538-1538/? D/Client: result: call : hello, arg: id=22 , bundle: 21, 线程id:Binder:1686_3

2020-09-27 12:12:17.364 1538-1538/? D/Client: result: call : hello, arg: id=23 , bundle: 22, 线程id:Binder:1686_3

2020-09-27 12:12:17.366 1538-1538/? D/Client: result: call : hello, arg: id=24 , bundle: 23, 线程id:Binder:1686_3

2020-09-27 12:12:17.369 1538-1538/? D/Client: result: call : hello, arg: id=25 , bundle: 24, 线程id:Binder:1686_3

2020-09-27 12:12:17.371 1538-1538/? D/Client: result: call : hello, arg: id=26 , bundle: 25, 线程id:Binder:1686_3

2020-09-27 12:12:17.373 1538-1538/? D/Client: result: call : hello, arg: id=27 , bundle: 26, 线程id:Binder:1686_3

2020-09-27 12:12:17.376 1538-1538/? D/Client: result: call : hello, arg: id=28 , bundle: 27, 线程id:Binder:1686_3

2020-09-27 12:12:17.379 1538-1538/? D/Client: result: call : hello, arg: id=29 , bundle: 28, 线程id:Binder:1686_3

2020-09-27 12:12:17.381 1538-1538/? D/Client: result: call : hello, arg: id=30 , bundle: 29, 线程id:Binder:1686_3

2020-09-27 12:12:17.384 1538-1538/? D/Client: result: call : hello, arg: id=31 , bundle: 30, 线程id:Binder:1686_3

2020-09-27 12:12:17.387 1538-1538/? D/Client: result: call : hello, arg: id=32 , bundle: 31, 线程id:Binder:1686_3

2020-09-27 12:12:17.390 1538-1538/? D/Client: result: call : hello, arg: id=33 , bundle: 32, 线程id:Binder:1686_3

2020-09-27 12:12:17.392 1538-1538/? D/Client: result: call : hello, arg: id=34 , bundle: 33, 线程id:Binder:1686_3

2020-09-27 12:12:17.395 1538-1538/? D/Client: result: call : hello, arg: id=35 , bundle: 34, 线程id:Binder:1686_3

2020-09-27 12:12:17.397 1538-1538/? D/Client: result: call : hello, arg: id=36 , bundle: 35, 线程id:Binder:1686_3

2020-09-27 12:12:17.400 1538-1538/? D/Client: result: call : hello, arg: id=37 , bundle: 36, 线程id:Binder:1686_3

2020-09-27 12:12:17.402 1538-1538/? D/Client: result: call : hello, arg: id=38 , bundle: 37, 线程id:Binder:1686_3

2020-09-27 12:12:17.405 1538-1538/? D/Client: result: call : hello, arg: id=39 , bundle: 38, 线程id:Binder:1686_3

2020-09-27 12:12:17.407 1538-1538/? D/Client: result: call : hello, arg: id=40 , bundle: 39, 线程id:Binder:1686_3

2020-09-27 12:12:17.410 1538-1538/? D/Client: result: call : hello, arg: id=41 , bundle: 40, 线程id:Binder:1686_3

2020-09-27 12:12:17.413 1538-1538/? D/Client: result: call : hello, arg: id=42 , bundle: 41, 线程id:Binder:1686_2

2020-09-27 12:12:17.415 1538-1538/? D/Client: result: call : hello, arg: id=43 , bundle: 42, 线程id:Binder:1686_3

2020-09-27 12:12:17.417 1538-1538/? D/Client: result: call : hello, arg: id=44 , bundle: 43, 线程id:Binder:1686_3

2020-09-27 12:12:17.420 1538-1538/? D/Client: result: call : hello, arg: id=45 , bundle: 44, 线程id:Binder:1686_3

2020-09-27 12:12:17.422 1538-1538/? D/Client: result: call : hello, arg: id=46 , bundle: 45, 线程id:Binder:1686_3

2020-09-27 12:12:17.424 1538-1538/? D/Client: result: call : hello, arg: id=47 , bundle: 46, 线程id:Binder:1686_3

2020-09-27 12:12:17.427 1538-1538/? D/Client: result: call : hello, arg: id=48 , bundle: 47, 线程id:Binder:1686_3

2020-09-27 12:12:17.429 1538-1538/? D/Client: result: call : hello, arg: id=49 , bundle: 48, 线程id:Binder:1686_2

2020-09-27 12:12:17.431 1538-1538/? D/Client: result: call : hello, arg: id=50 , bundle: 49, 线程id:Binder:1686_2

2020-09-27 12:12:17.433 1538-1538/? D/Client: result: call : hello, arg: id=51 , bundle: 50, 线程id:Binder:1686_2

2020-09-27 12:12:17.435 1538-1538/? D/Client: result: call : hello, arg: id=52 , bundle: 51, 线程id:Binder:1686_2

2020-09-27 12:12:17.437 1538-1538/? D/Client: result: call : hello, arg: id=53 , bundle: 52, 线程id:Binder:1686_2

2020-09-27 12:12:17.439 1538-1538/? D/Client: result: call : hello, arg: id=54 , bundle: 53, 线程id:Binder:1686_2

2020-09-27 12:12:17.441 1538-1538/? D/Client: result: call : hello, arg: id=55 , bundle: 54, 线程id:Binder:1686_2

2020-09-27 12:12:17.443 1538-1538/? D/Client: result: call : hello, arg: id=56 , bundle: 55, 线程id:Binder:1686_2

2020-09-27 12:12:17.445 1538-1538/? D/Client: result: call : hello, arg: id=57 , bundle: 56, 线程id:Binder:1686_2

2020-09-27 12:12:17.447 1538-1538/? D/Client: result: call : hello, arg: id=58 , bundle: 57, 线程id:Binder:1686_2

2020-09-27 12:12:17.449 1538-1538/? D/Client: result: call : hello, arg: id=59 , bundle: 58, 线程id:Binder:1686_2

2020-09-27 12:12:17.451 1538-1538/? D/Client: result: call : hello, arg: id=60 , bundle: 59, 线程id:Binder:1686_2

2020-09-27 12:12:17.454 1538-1538/? D/Client: result: call : hello, arg: id=61 , bundle: 60, 线程id:Binder:1686_2

2020-09-27 12:12:17.456 1538-1538/? D/Client: result: call : hello, arg: id=62 , bundle: 61, 线程id:Binder:1686_2

2020-09-27 12:12:17.458 1538-1538/? D/Client: result: call : hello, arg: id=63 , bundle: 62, 线程id:Binder:1686_2

2020-09-27 12:12:17.460 1538-1538/? D/Client: result: call : hello, arg: id=64 , bundle: 63, 线程id:Binder:1686_2

2020-09-27 12:12:17.462 1538-1538/? D/Client: result: call : hello, arg: id=65 , bundle: 64, 线程id:Binder:1686_2

2020-09-27 12:12:17.464 1538-1538/? D/Client: result: call : hello, arg: id=66 , bundle: 65, 线程id:Binder:1686_2

2020-09-27 12:12:17.466 1538-1538/? D/Client: result: call : hello, arg: id=67 , bundle: 66, 线程id:Binder:1686_2

2020-09-27 12:12:17.468 1538-1538/? D/Client: result: call : hello, arg: id=68 , bundle: 67, 线程id:Binder:1686_2

2020-09-27 12:12:17.471 1538-1538/? D/Client: result: call : hello, arg: id=69 , bundle: 68, 线程id:Binder:1686_2

2020-09-27 12:12:17.473 1538-1538/? D/Client: result: call : hello, arg: id=70 , bundle: 69, 线程id:Binder:1686_2

2020-09-27 12:12:17.476 1538-1538/? D/Client: result: call : hello, arg: id=71 , bundle: 70, 线程id:Binder:1686_2

2020-09-27 12:12:17.478 1538-1538/? D/Client: result: call : hello, arg: id=72 , bundle: 71, 线程id:Binder:1686_2

2020-09-27 12:12:17.480 1538-1538/? D/Client: result: call : hello, arg: id=73 , bundle: 72, 线程id:Binder:1686_2

2020-09-27 12:12:17.482 1538-1538/? D/Client: result: call : hello, arg: id=74 , bundle: 73, 线程id:Binder:1686_2

2020-09-27 12:12:17.485 1538-1538/? D/Client: result: call : hello, arg: id=75 , bundle: 74, 线程id:Binder:1686_2

2020-09-27 12:12:17.487 1538-1538/? D/Client: result: call : hello, arg: id=76 , bundle: 75, 线程id:Binder:1686_2

2020-09-27 12:12:17.490 1538-1538/? D/Client: result: call : hello, arg: id=77 , bundle: 76, 线程id:Binder:1686_2

2020-09-27 12:12:17.492 1538-1538/? D/Client: result: call : hello, arg: id=78 , bundle: 77, 线程id:Binder:1686_2

2020-09-27 12:12:17.494 1538-1538/? D/Client: result: call : hello, arg: id=79 , bundle: 78, 线程id:Binder:1686_2

2020-09-27 12:12:17.496 1538-1538/? D/Client: result: call : hello, arg: id=80 , bundle: 79, 线程id:Binder:1686_2

2020-09-27 12:12:17.499 1538-1538/? D/Client: result: call : hello, arg: id=81 , bundle: 80, 线程id:Binder:1686_2

2020-09-27 12:12:17.501 1538-1538/? D/Client: result: call : hello, arg: id=82 , bundle: 81, 线程id:Binder:1686_2

2020-09-27 12:12:17.503 1538-1538/? D/Client: result: call : hello, arg: id=83 , bundle: 82, 线程id:Binder:1686_2

2020-09-27 12:12:17.505 1538-1538/? D/Client: result: call : hello, arg: id=84 , bundle: 83, 线程id:Binder:1686_2

2020-09-27 12:12:17.507 1538-1538/? D/Client: result: call : hello, arg: id=85 , bundle: 84, 线程id:Binder:1686_2

2020-09-27 12:12:17.509 1538-1538/? D/Client: result: call : hello, arg: id=86 , bundle: 85, 线程id:Binder:1686_2

2020-09-27 12:12:17.511 1538-1538/? D/Client: result: call : hello, arg: id=87 , bundle: 86, 线程id:Binder:1686_2

2020-09-27 12:12:17.513 1538-1538/? D/Client: result: call : hello, arg: id=88 , bundle: 87, 线程id:Binder:1686_2

2020-09-27 12:12:17.516 1538-1538/? D/Client: result: call : hello, arg: id=89 , bundle: 88, 线程id:Binder:1686_2

2020-09-27 12:12:17.518 1538-1538/? D/Client: result: call : hello, arg: id=90 , bundle: 89, 线程id:Binder:1686_2

2020-09-27 12:12:17.521 1538-1538/? D/Client: result: call : hello, arg: id=91 , bundle: 90, 线程id:Binder:1686_3

2020-09-27 12:12:17.523 1538-1538/? D/Client: result: call : hello, arg: id=92 , bundle: 91, 线程id:Binder:1686_2

2020-09-27 12:12:17.525 1538-1538/? D/Client: result: call : hello, arg: id=93 , bundle: 92, 线程id:Binder:1686_2

2020-09-27 12:12:17.527 1538-1538/? D/Client: result: call : hello, arg: id=94 , bundle: 93, 线程id:Binder:1686_3

2020-09-27 12:12:17.529 1538-1538/? D/Client: result: call : hello, arg: id=95 , bundle: 94, 线程id:Binder:1686_2

2020-09-27 12:12:17.531 1538-1538/? D/Client: result: call : hello, arg: id=96 , bundle: 95, 线程id:Binder:1686_2

2020-09-27 12:12:17.532 1538-1538/? D/Client: result: call : hello, arg: id=97 , bundle: 96, 线程id:Binder:1686_2

2020-09-27 12:12:17.534 1538-1538/? D/Client: result: call : hello, arg: id=98 , bundle: 97, 线程id:Binder:1686_2

2020-09-27 12:12:17.536 1538-1538/? D/Client: result: call : hello, arg: id=99 , bundle: 98, 线程id:Binder:1686_2

2020-09-27 12:12:17.539 1538-1538/? D/Client: result: call : hello, arg: id=100 , bundle: 99, 线程id:Binder:1686_2

2、支持回调

这个过程我们需要借助call方法的Bundle参数,众所周知,bundle支持的数据类型中,支持binder传输,参考intent传输binder的方式

/**

* Inserts an {@link IBinder} value into the mapping of this Bundle, replacing

* any existing value for the given key. Either key or value may be null.

*

*

You should be very careful when using this function. In many

* places where Bundles are used (such as inside of Intent objects), the Bundle

* can live longer inside of another process than the process that had originally

* created it. In that case, the IBinder you supply here will become invalid

* when your process goes away, and no longer usable, even if a new process is

* created for you later on.

*

* @param key a String, or null

* @param value an IBinder object, or null

*/

public void putBinder(@Nullable String key, @Nullable IBinder value) {

unparcel();

mMap.put(key, value);

}

因此对于回调问题,我们只需要简单借助普通AIDL即可

client端:

try {

Bundle bundle = new Bundle();

RemoteCallback listener = new RemoteCallback(new RemoteCallback.OnResultListener() {

@Override

public void onResult(Bundle result) {

Log.d(TAG, "receive result do something");

}

}, new Handler());

bundle.putParcelable("listener", listener);

Uri uri = Uri.parse("you wanted content provider uri");

getApplicationContext().getContentResolver().call(uri, "LISTEN", null, bundle);

Log.d(TAG, "call provider");

} catch (Exception e) {

e.printStackTrace();

}

server端:

extras.setClassLoader(RemoteCallback.class.getClassLoader()); //注意classloader问题

final RemoteCallback callback = (RemoteCallback) extras.getParcelable("listener");

if (callback != null) {

mListener = new Runnable() {

@Override

public void run() {

callback.sendResult(new Bundle("you want send info"));

}

};

}

注意:

Service 中通过 AIDL 提供的接口并不是线程安全的,同理 ContentProvider 底层也是使用 Binder,同样不是线程安全的,至于是否需要做多线程保护,看业务而定,最好是做好多线程同步,以防万一

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值