本项目已经上传至码云,有兴趣的哥们可以参考。
码云:https://git.oschina.net/xuzhaoyu/functions.git
最近在做构建一个股票类App架构的时候,考虑到Fragment很多,Fragment与Activity之间的通讯机制的设计就显得比较重要。
用什么样的方式进行通讯呢?两行哥脑海中划过一些想法:
- 直接在Fragment中getActivity()并强转为XXXActivity,利用XXXActivity.method()调用(不安全,为什么呢?两行哥卖个关子,交给各位看官自己思考);
- 通过广播进行通讯(包括底层基于广播的EventBus等),这是一个不错的方法,不过广播的注册解绑要特别留心,时刻注意以防内存泄露;
- 通过封装的通讯类进行通讯,这也是本文介绍的方式。
通常来说,Fragment向Activity通讯,多数目的是为了在Fragment中调用Activity的方法。比如,SlidingMenu(第三方侧滑菜单)或ToolBar依附于Activity而存在,而如果依附于该Activity的Fragment想要调用某方法来改变SlidingMenu或ToolBar的状态,就属于Fragment调用Activity中的方法的范畴。
我们先对方法进行分类,方法无外乎四种:
- 无参无反方法;
- 有参无反方法;
- 无参有反方法;
- 有参有反方法。
那么我们自定义用于通讯的类,定义五种内部类(一个基类和四个子类),分别对应这四种方法:
public class Functions {
......
//方法的基类,并定义一个有参构造方法
public abstract static class BaseFunction {
//成员变量:方法名
public String mFunctionName;
public BaseFunction(String functionName) {
mFunctionName = functionName;
}
}
/**
* 无参无反的方法
*/
public abstract static class Function extends BaseFunction {
public Function(String functionName) {
super(functionName);
}
public abstract void function();
}
/**
* 有参无反的方法
*
* @param <Params> 方法参数
*/
public abstract static class FunctionWithParams<Params> extends BaseFunction {
public FunctionWithParams(String functionName) {
super(functionName);
}
public abstract void function(Params params);
}
/**
* 无参有反的方法
*
* @param <Results> 方法返回值
*/
public abstract static class FunctionWithResults<Results> extends BaseFunction {
public FunctionWithResults(String functionName) {
super(functionName);
}
public abstract Results function();
}
/**
* 有参有反的方法
*
* @param <Params> 方法参数
* @param <Results> 方法返回值
*/
public abstract static class FunctionWithParamsAndResults<Params, Results> extends BaseFunction {
public FunctionWithParamsAndResults(String functionName) {
super(functionName);
}
public abstract Results function(Params params);
}
......
}
同时我们在这个类中定义四个集合,分别用来存放这四种方法,并定义将方法添加到集合中的方法。为了提高性能,这里使用了ArrayMap。
public class Functions {
......
/**
* 存放四类方法的集合
*/
private ArrayMap<String, Function> mFunctionMap = new ArrayMap<>();
private ArrayMap<String, FunctionWithParams> mFunctionWithParamsMap = new ArrayMap<>();
private ArrayMap<String, FunctionWithResults> mFunctionWithResultsMap = new ArrayMap<>();
private ArrayMap<String, FunctionWithParamsAndResults> mFunctionWithParamsAndResultsMap = new ArrayMap<>();
/**
* 添加无参无反方法
*
* @param function 被添加的方法
*/
public Functions addFunction(Function function) {
if (function != null) {
mFunctionMap.put(function.mFunctionName, function);
}
return this;
}
/**
* 添加有参无反的方法
*
* @param function 被添加的方法
*/
public Functions addFunction(FunctionWithParams function) {
if (function != null) {
mFunctionWithParamsMap.put(function.mFunctionName, function);
}
return this;
}
/**
* 添加无参有反的方法
*
* @param function 被添加的方法
*/
public Functions addFunction(FunctionWithResults function) {
if (function != null) {
mFunctionWithResultsMap.put(function.mFunctionName, function);
}
return this;
}
/**
* 添加有参有反的方法
*
* @param function 被添加的方法
*/
public Functions addFunction(FunctionWithParamsAndResults function) {
if (function != null) {
mFunctionWithParamsAndResultsMap.put(function.mFunctionName, function);
}
return this;
}
......
}
当我们定义完这四种方法类型、存放方法的集合以及添加方法到集合中的方法后,就该考虑如何调用集合中的方法,基本思路是传入方法名字符串,如果集合中存在该方法名,则调用该方法。代码逻辑如下:
public class Functions {
......
/**
* 调用无参无反的方法
*
* @param functionName 被调用方法的名字
*/
public void invokeFun(String functionName) {
Function function = mFunctionMap.get(functionName);
if (function != null) {
function.function();
}
}
/**
* 调用有参无反的方法
*
* @param functionName 被调用方法的名字
* @param params 被调用方法的参数
* @param <Params> 被调用方法的参数泛型
*/
public <Params> void invokeFunWithParams(String functionName, Params params) {
FunctionWithParams functionWithParams = mFunctionWithParamsMap.get(functionName);
if (functionWithParams != null) {
functionWithParams.function(params);
}
}
/**
* 调用无参有反的方法
*
* @param functionName 被调用方法的名字
* @param clazz 被调用方法返回值的类(.class)
* @param <Results> 被调用方法的返回值泛型
* @return 被调用方法的返回值
*/
public <Results> Results invokeFunWithResult(String functionName, Class<Results> clazz) {
FunctionWithResults functionWithResults = mFunctionWithResultsMap.get(functionName);
if (functionWithResults != null) {
return clazz.cast(functionWithResults.function());
}
return null;
}
/**
* 调用有参有反的方法
*
* @param functionName 被调用方法的名字
* @param params 被调用方法的参数
* @param clazz 被调用方法返回值的类(.class)
* @param <Params> 被调用方法的参数泛型
* @param <Results> 被调用方法的返回值泛型
* @return 被调用方法的返回值
*/
public <Params, Results> Results invokeFunWithParamsAndResults(String functionName, Params params, Class<Results> clazz) {
FunctionWithParamsAndResults functionWithParamsAndResults = mFunctionWithParamsAndResultsMap.get(functionName);
if (functionWithParamsAndResults != null) {
return clazz.cast(functionWithParamsAndResults.function(params));
}
return null;
}
......
}
这个类就此完成。附上完整代码:
public class Functions {
public abstract static class BaseFunction {
public String mFunctionName;
public BaseFunction(String functionName) {
mFunctionName = functionName;
}
}
public abstract static class Function extends BaseFunction {
public Function(String functionName) {
super(functionName);
}
public abstract void function();
}
public abstract static class FunctionWithParams<Params> extends BaseFunction {
public FunctionWithParams(String functionName) {
super(functionName);
}
public abstract void function(Params params);
}
public abstract static class FunctionWithResults<Results> extends BaseFunction {
public FunctionWithResults(String functionName) {
super(functionName);
}
public abstract Results function();
}
public abstract static class FunctionWithParamsAndResults<Params, Results> extends BaseFunction {
public FunctionWithParamsAndResults(String functionName) {
super(functionName);
}
public abstract Results function(Params params);
}
private ArrayMap<String, Function> mFunctionMap = new ArrayMap<>();
private ArrayMap<String, FunctionWithParams> mFunctionWithParamsMap = new ArrayMap<>();
private ArrayMap<String, FunctionWithResults> mFunctionWithResultsMap = new ArrayMap<>();
private ArrayMap<String, FunctionWithParamsAndResults> mFunctionWithParamsAndResultsMap = new ArrayMap<>();
public void invokeFun(String functionName) {
Function function = mFunctionMap.get(functionName);
if (function != null) {
function.function();
}
}
public <Params> void invokeFunWithParams(String functionName, Params params) {
FunctionWithParams functionWithParams = mFunctionWithParamsMap.get(functionName);
if (functionWithParams != null) {
functionWithParams.function(params);
}
}
public <Results> Results invokeFunWithResult(String functionName, Class<Results> clazz) {
FunctionWithResults functionWithResults = mFunctionWithResultsMap.get(functionName);
if (functionWithResults != null) {
return clazz.cast(functionWithResults.function());
}
return null;
}
public <Params, Results> Results invokeFunWithParamsAndResults(String functionName, Params params, Class<Results> clazz) {
FunctionWithParamsAndResults functionWithParamsAndResults = mFunctionWithParamsAndResultsMap.get(functionName);
if (functionWithParamsAndResults != null) {
return clazz.cast(functionWithParamsAndResults.function(params));
}
return null;
}
public Functions addFunction(Function function) {
if (function != null) {
mFunctionMap.put(function.mFunctionName, function);
}
return this;
}
public Functions addFunction(FunctionWithParams function) {
if (function != null) {
mFunctionWithParamsMap.put(function.mFunctionName, function);
}
return this;
}
public Functions addFunction(FunctionWithResults function) {
if (function != null) {
mFunctionWithResultsMap.put(function.mFunctionName, function);
}
return this;
}
public Functions addFunction(FunctionWithParamsAndResults function) {
if (function != null) {
mFunctionWithParamsAndResultsMap.put(function.mFunctionName, function);
}
return this;
}
}
让我们来看看如何在实际代码中通过这个类实现通讯。举一个小例子:
在BaseFragment中定义Functions成员变量,BaseFragment中代码:
//定义Functions类的成员变量
private Functions mFunctions;
//定义Setter()和Getter()方法
public void setFunctions(Functions functions) {
mFunctions = functions;
}
public Functions getFunctions() {
return mFunctions;
}
MainActivity持有一个Fragment的引用,同时在MainActivity中有一个mSlidingMenu的成员变量,该成员变量有一个toggle()的方法。我们将这个方法设置给BaseFragment的Functions变量。MainActivity中代码:
public static final String FUN_SLIDING_MENU_TOGGLE = "FUN_SLIDING_MENU_TOGGLE";
baseFragment = FragmentFactory.getFragment(0);
baseFragment.setFunctions(new Functions().addFunction(new Functions.Function(FUN_SLIDING_MENU_TOGGLE) {
@Override
public void function() {
mSlidingMenu.toggle();
}
}));
那么,我们在Fragment中想要调用MainActivity中mSlidingMenu这个成员变量的toggle()方法,Fragment中代码:
getFunctions().invokeFun(MainActivity.FUN_SLIDING_MENU_TOGGLE);
本文到此结束。还有几个问题留给各位看官思考:
如果该方法有不定数量的参数该如何在通讯类中封装呢?
思路一:封装的参数改为集合或数组的形式?
思路二:将参数再次封装为参数对象,该参数对象含有多个成员变量(即参数)?
......
网友评论