作为 Android 四大基础组件之一的 ContentProvider 本来它的作用只是提供内容性质的跨进程访问。APP-A通过APP-B的ContentProvider相关实现,可以获取B的向外暴露的SQL或者SP数据,但是A如何通知B去更新ContentProvider的相关内容?
传统方式有1:广播;2:AIDL,弊端是使用流程相对繁琐
在 API 11 (Android 3.0) 中,ContentProvider 加入了一个新的方法,可以用来进行跨进程的方法调用,ContentProvider 中这个方法的定义如下:
Bundle call(String method, String arg, Bundle extras)
看看具体实现
A中实现
private void update(String status) {
getContext().getContentResolver().call(ACCOUNT_URI, "STATUS", status, new Bundle());
}
B中实现
@Override
public Bundle call(String method, String arg, Bundle extras) {
if ("STATUS".equals(method)) {
//dosomething
}
return null;
}
A中就能触发B的具体逻辑操作,类似复写,B也可以触发A的操作
我们实现一个基础库,通过ContentProvider+反射实现A调用B接口,B调用A接口,简化使用流程
3.1、实现一个基础IContentProvider,A/B中都继承
@Nullable
@Override
public Bundle call(@NonNull String method, @Nullable String arg, @Nullable Bundle in) {
if (in == null) {
return null;
}
long start = SystemClock.elapsedRealtime();
Bundle response = new Bundle();
in.setClassLoader(Par.class.getClassLoader());
Parcelable returnResponse = in.getParcelable(PEVENT_KEY_RESPONSE);
response.putParcelable(PEVENT_KEY_RESPONSE, returnResponse);
try {
String calling = getCallingPackage();
long callingTime = SystemClock.elapsedRealtime();
PEventLog.e(TAG, "used time calling:" + (callingTime - start));
if (!TextUtils.isEmpty(calling)) {
in.putString(PEVENT_KEY_CALLING_PACKAGE, calling);
}
String route = in.getString(PEVENT_KEY_ROUTE);
int flags = in.getInt(PEVENT_KEY_FLAGS);
if (TextUtils.isEmpty(route)) {
throw new NotFoundRouteException(route + " was not found");
}
ArrayDeque callers = PServiceManager.getInstance().lookupMethods(route);
if (callers == null || callers.isEmpty()) {
throw new NotFoundRouteException(route + " was not found");
}
Iterator iterators = callers.iterator();
while (iterators.hasNext()) {
MethodInvoker methodInvoker = iterators.next();
methodInvoker.invoke(in, response);
}
response.putInt(PEVENT_KEY_RESPONSE_CODE, PEVENT_RESPONSE_RESULE_SUCCESS);
} catch (NoSuchMethodException | InvocationTargetException e) {
e.printStackTrace();
response.putInt(PEVENT_KEY_RESPONSE_CODE, PEVENT_RESPONSE_RESULE_NO_SUCH_METHOD);
} catch (NotFoundRouteException e) {
response.putInt(PEVENT_KEY_RESPONSE_CODE, PEVENT_RESPONSE_RESULE_NOT_FOUND_ROUTE);
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
response.putInt(PEVENT_KEY_RESPONSE_CODE, PEVENT_RESPONSE_RESULE_ILLEGALACCESS);
} catch (Throwable e) {
e.printStackTrace();
response.putInt(PEVENT_KEY_RESPONSE_CODE, PEVENT_RESPONSE_RESULE_REMOTE_EXCEPTION);
}
return response;
}
A中
PEvent pEvent = PEvent.newBuilder(MainActivity.this).setAuthority("com.pevent.example").build();
Bundle bundle = pEvent.route("/show/age").withString("age", "20").post();
Bundle post(@NonNull Bundle in) {
ContentResolver contentResolver = mContext.getContentResolver();
Bundle out = null;
try {
out = contentResolver.call(base, "", null, in);
parseReponse(in, out);
} catch (Throwable e) {
e.printStackTrace();
}
return out;
}
B中
@MainThread
@Route("/show/age")
public void showAge(final Bundle in, Bundle out) {
out.putString("age", "10");
String name = in.getString("age");
tv.setText(name);
}