美文网首页Android开发经验谈
〔两行哥〕封装通讯类实现Fragment与Activity通讯

〔两行哥〕封装通讯类实现Fragment与Activity通讯

作者: 两行哥 | 来源:发表于2017-07-10 23:15 被阅读69次

    本项目已经上传至码云,有兴趣的哥们可以参考。

    码云: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);
    

    本文到此结束。还有几个问题留给各位看官思考:
    如果该方法有不定数量的参数该如何在通讯类中封装呢?
    思路一:封装的参数改为集合或数组的形式?
    思路二:将参数再次封装为参数对象,该参数对象含有多个成员变量(即参数)?
    ......

    相关文章

      网友评论

        本文标题:〔两行哥〕封装通讯类实现Fragment与Activity通讯

        本文链接:https://www.haomeiwen.com/subject/zmguhxtx.html