您的位置:首页 > 移动开发 > Android开发

聊聊Android应用实现跨进程调用

2016-04-04 11:10 483 查看

Android应用实现跨进程调用

关于Android应用如何实现跨进程调用这是一个比较老的话题了。我们先来看看Android为应用开发者提供了哪些跨进程调用的方法?

主要方法:

startActivity

sendBroadcast

startService

Messenger

AIDL

Provider

简述

startActivity, sendBroadcast,startService 使用都比较简单。通常使用在传递简单消息,通知另外一个进程。异步并且得不到反馈。AIDL是android推荐使用的,但是客户端调用稍微复杂,不利于接口封装(客户端必须先bind,然后才可以调用)。Messenger实际上是在AIDL的基础上进行了封装。可以更好的结合handler来使用,相对较为简单,但是也存在不利于接口封装的问题。本文我们主要想讲下provider来实现跨进程调用。

简单例子

我们主要用provider的call方法来实现跨进程调用。我们在这里定义三个类,其实不需要数据库操作,只是简单的提供接口的话,ISDbHelper也可以不用。



ISProvider

ISProvider 继承自ContentProvider 实现其中的call方法,在call方法中调用ProviderDispatcher的中的方法。这里有个技巧,就是用反射来调用ProviderDispatcher中的方法,这样写的好处是:我们不用大量的写if else,并且ProviderDispatcher中添加方法以后ISProvider 中可以不用修改。

类声明代码片段

public class ISProvider extends ContentProvider


成员变量代码片段

private ProviderDispatcher mProviderDispatcher;
private Class<?> providerDispatcherClass;


call方法代码片段

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

String prefix = "[method: " + method + "]" + " [ arg: " + arg + "]" ;

if (providerDispatcherClass == null) {
mProviderDispatcher = new ProviderDispatcher(getContext());
providerDispatcherClass = mProviderDispatcher.getClass();
}

try {
Method providerDispatcherClassMethod = providerDispatcherClass.getMethod(method, Bundle.class);
Object object = providerDispatcherClassMethod.invoke(mProviderDispatcher, extras);
if (object != null) {
return (Bundle)object;
} else {
return null;
}
}catch (NoSuchMethodException e) {
LOG.error(TAG, prefix + " invoke failed(NoSuchMethodException)", e);
} catch (IllegalAccessException e) {
LOG.error(TAG, prefix + " invoke failed(IllegalAccessException)", e);
} catch (IllegalArgumentException e) {
LOG.error(TAG, prefix + " invoke failed(IllegalArgumentException)", e);
} catch (InvocationTargetException e) {
LOG.error(TAG, prefix + " invoke failed(InvocationTargetException)",   e.getTargetException());
} catch (Exception e) {
LOG.error(TAG, prefix + " invoke failed(Exception)", e);
} catch (Throwable e) {
LOG.error(TAG, prefix + " invoke failed(Throwable)", e);
}
return null;
}


ProviderDispatcher

利用上面反射的写法的话ProviderDispatcher中的方法必须是这样的写法

public Bundle getInstalledAppList(Bundle input)


参数数据类型

由于call方法是用bundle来传递数据的,用人问bundle怎么传递list,看下面:

input.putParcelableArrayList("key", (ArrayList<? extends Parcelable>) bundleList);


ISAgent

我们在ISAgent类中调用provider中的call方法,封装成调用者方便使用的方法



示例代码片段:

public List<AppInfo> getInstalledAppList() throws ISException {
Bundle bundle = new Bundle();
KVUtils.put(bundle, Constant.KEY_APP_ID, appId);
KVUtils.put(bundle, Constant.KEY_BIZ_ID, Constant.BIZ_APP);
ContentResolver resolver =context.getContentResolver();
Bundle ret = resolver.call(Uri.parse(ISColumn.CONTENT + ISColumn.AUTHORITY), "getInstalledAppList", null, bundle);
if (ret == null) {
LOG.error(TAG, "getInstalledAppList failed");
return null;
} else {
int rcode = KVUtils.getInt(ret, Constant.KEY_RCODE, Rcode.FAIL);
String msg = KVUtils.getString(ret, Constant.KEY_MESSAGE,"");
if (rcode != Rcode.OK) {
throw new ISException(rcode, msg);
} else {
List<Bundle> bundles = ret.getParcelableArrayList("getInstalledAppList");
return AppInfo.bundlesToApps(context,bundles);
}
}
}


利用provider提供接口我们最好增加相应的权限,这样可以提供apk的安全性。

在主apk中声明权限

<permission android:name="infinite.sapce.permission.DATA" />


<provider
android:name="com.test.android.space.provider.ISProvider"
android:authorities="com.test.android.space.provider"
android:permission="infinite.sapce.permission.DATA"
android:exported="true" />


调用者apk权限

这样调用者要想使用就必须在manifest做下面声明

<uses-permission android:name="infinite.sapce.permission.DATA" />
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: