我们最常常遇到的UI组件通信有,activity和activity,activity和fragment。方法很多,开源的项目也有,如rxbus,eventbus,这些框架多多少少都有缺点,如不支持返回值。使用event还使得代码及其难维护。
现在自己手写实现一个UI组件通信框架,支持参数,返回值。
该框架的主要思想是对接口进行面向对象,进行抽象。
我们知道,一个接口中的方法,一定有方法名。至于参数和返回值,或可有可无,根据业务而定。
因此我们对其定义一个基本的抽象
/** * 对接口的抽象 */ public static abstract class Function { private String mFunctionName; public String getFunctionName() { return mFunctionName; } private Function(String functionName) { mFunctionName = functionName; } }至于方法体的样式,就是四类了。
1,无参无返回值的
/** * no params no result */ public static abstract class FunctionNPNR extends Function { public FunctionNPNR(String functionName) { super(functionName); } public abstract void onInvoke(Bundle data); }
2,无参有返回值的
/** * no params with result * * @param <Result> */ public static abstract class FunctionNPWR<Result> extends Function { public FunctionNPWR(String functionName) { super(functionName); } public abstract Result onInvoke(Bundle data); }3,有参无返回值的
/** * no result with params */ public static abstract class FunctionNRWP extends Function { public FunctionNRWP(String functionName) { super(functionName); } public abstract void onInvoke(Map, String> params, Bundle data); }
4,有参有返回值的
/** * with result with params */ public static abstract class FunctionWRWP<Result> extends Function { public FunctionWRWP(String functionName) { super(functionName); } public abstract Result onInvoke(Map, String> params, Bundle data); }
对外暴露注册的api
/** * regist function in place where your busness need * * @param f */ public void registFunc(Function f) { mFunctionHashMap.put(f.getFunctionName(), f); }
对外暴露调用的api
/** * trigger the function you have registed in everywhere you want * * @param funcName, 函数名 * @param clazz, 触发后的返回值类型字节码 * @param params ,触发参数 * @param data ,给注册者的数据 * @param <T> * @return */ public <T> T invokeFunc(String funcName, Class<T> clazz, Map, String> params, Bundle data) { Function function = mFunctionHashMap.get(funcName); if (function == null) { return null; // throw new IllegalArgumentException("no such function:" + funcName + ",have you regist " + "this function somewhere first?"); } data = data == null ? new Bundle() : data; if (clazz != null) { //1 no params with result if (params == null) { if (function instanceof FunctionNPWR) { return clazz.cast(((FunctionNPWR) function).onInvoke(data)); } else { return throwException(function, FunctionNPWR.class); } } else { //2 with params with result if (function instanceof FunctionWRWP) { return clazz.cast(((FunctionWRWP) function).onInvoke(params, data)); } else { return throwException(function, FunctionWRWP.class); } } } else { //1 no params no result if (params == null) { if (function instanceof FunctionNPNR) { ((FunctionNPNR) function).onInvoke(data); } else { return throwException(function, FunctionNPNR.class); } } else { //2 with params no result ((FunctionNRWP) function).onInvoke(params, data); } } return null; }
/** * 当调用参数不匹配时,抛出异常 * @param function * @param functionClazz * @param <T> * @return */ private <T> T throwException(Function function, Class extends Function> functionClazz) { throw new ClassCastException("the function " + function.getFunctionName() + " when regist is not " + "match:" + functionClazz); }
最后将上面的类或者方法放入一个单例类中
public class Functions { private static HashMap, Function> mFunctionHashMap = new HashMap<>(); private Functions() { } public static Functions getInstance() { return mSingleton.get(); } private static Singleton mSingleton = new Singleton () { @Override protected Functions create() { return new Functions(); } };}
框架就完成了。
接下来进行使用。
业务场景如下,页面的titlebar隶属于activity,该activity中间容器包含的是fragment,点击titlebar的刷新控件,fragment进行刷新。刷新“今天”的。
在fragment中进行注册:
Functions.getInstance().registFunc(new Functions.FunctionNPNR("orderList") { @Override public void onInvoke(Bundle data) { Toast.makeText(Main2Activity.this, "" + data.get("date"), Toast.LENGTH_SHORT).show(); } });
在activity中进行调用:
findViewById(R.id.tv).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //no param no result,告诉注册组件找出“今天”的订单 Bundle bundle = new Bundle(); bundle.putString("date", "今天"); Functions.getInstance().invokeFunc("orderList", null, null, bundle); } });
如果需要有参有返回值,注册时则选用FunctionWRWP,其他以此类推,根据业务需求选择对应的function类型。