ContentProvider call实现跨进程通信

github.com/wengeoo/PEvent.git

1、ContentProvider query

 作为 Android 四大基础组件之一的 ContentProvider 本来它的作用只是提供内容性质的跨进程访问。APP-A通过APP-B的ContentProvider相关实现,可以获取B的向外暴露的SQL或者SP数据,但是A如何通知B去更新ContentProvider的相关内容?

 传统方式有1:广播;2:AIDL,弊端是使用流程相对繁琐   

2、ContentProvider call

在 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的操作

3、继续扩展

我们实现一个基础库,通过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);
    }

你可能感兴趣的:(android,java)