献给android原生应用层开发初学者技术架构选型和整合的方案思路(五)

续前篇《献给android原生应用层开发初学者技术架构选型和整合的方案思路(四)》 

封装最终的 BaseFragment,取名CoreFragment,继承上一步封装的SwipeBackSupportFragment,因此拥有了MVVM,RxLifeCycle,SwipeBack 等特性。以后业务 Fragment均可继承此 CoreFragment,当然如果您需要在部分业务上不想强制实现 CoreFragment中的抽象方法,您也可以只继承到SwipeBackSupportFragment,然后实现自己特定的功能。本 CoreFragment 也是一个 abstract class,并且要集成 Arouter注入,EventBus 事件总线,集成LeakCanary的内存泄露检测,集成 Epoxy库对 MvRx 的state changes 的响应,提供 Default 转场动画,以及配置统一的 fragment 的退出策略公用函数等。

  1. Arouter 的参数injection以及EventBus 的 load与 unload,统一采用了一个 boolean 开关函数来控制是否启用。按官方文档及对组件生命周期的运行机制的了解,Arouter 的 injection 启用可在onViewCreated生命周期回调函数中启用,EventBus 可在 onStart中启用。示例代码如下:
        @CallSuper
        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
            if (needUseARouterInjection()) {
                ARouter.getInstance().inject(this)
            }
        }
        @CallSuper
        override fun onStart() {
            super.onStart()
            //尽量比较晚注册和响应 eventBus 事件,界面 UI都确保生成好
            if (needRegisterEventBus()) {
                EventBusUtils.register(this)
            }
        }

    其中两个 needXXX的开关函数如下:

        /**
         * 是否需要注册 eventBus 的开关,由子类复写此方法,默认false 不注册
         */
        protected open fun needRegisterEventBus(): Boolean = false
    
        /**
         * 是否需要使用 ARouter 的自动参数注入
         * 默认为 true,即启用
         */
        protected open fun needUseARouterInjection(): Boolean = true

    needRegisterEventBus()默认为 false 的原因是,EventBus 在给注册的类扫描@Subscribe注解方法时,如果当前类中没有此注解但是注册了,运行时会报错,秉着约定编程代码量简化的原则,默认为 false 可解决实例子类全部要 override 此方法返回 true 的麻烦。另外封装了 EventBus 的两个 Util工具函数类,EventBusData<T>,EventBusUtils,前者是泛型 data class,包装要在 EventBusUtils#fun <T> post(data: T)中传递的对象类型。在子类实例中可按需要 override 这两个开关函数即可。

  2. Epoxy 库与 MvRx 的 MVVM 特性的集成。具体知识请参见第一篇文章中有关 Epoxy 构建复杂 RecycleView 的链接技术文章。以下为 MvRx State Change 与 Epoxy响应 State 的关键调用代码: 

        @CallSuper
        override fun invalidate() {
            recycleViewInstance.requestModelBuild()
        }

    其中关键的两个成员epoxyRecyclerView instance,epoxyController,前者定义为 lateinit 对象,后者委托给一个 abstract 函数,两者均留到子类实例化时 override。代码模板如下:

        lateinit var recycleViewInstance: EpoxyRecyclerView
    
        /**
         * the injected real epoxy controller instance
         */
        protected val epoxyControllerInstance by lazy { fetchEpoxyController() }
        
        abstract fun fetchEpoxyController(): EpoxyController

     

  3. 内存泄露检测工具LeakCanary的集成,按官方文档需求放置在 onDestory中调用,注意要先执行 super.onDestroy(通常在 override onDestroy 时,所有子类的代码均优先于 super.onDestroy 执行,如 RxLifeCycle的 ondestroy事件通知,又如下面示例中 EventBus 的 unregister)。关键代码如下:

        @CallSuper
        override fun onDestroy() {
            if (needRegisterEventBus()) {
                EventBusUtils.unregister(this)
            }
            super.onDestroy()
            try {
                //启用内存泄露检测
                val watcher = RootApplication.getRefWatcher(activity!!)
                watcher.watch(this)
            } catch (e: Exception) {
            }
        }

     

  4. 简单封装一个在主线程上执行闭包函数的公用方法 executeActions和一个针对 fragment 场景 scenario跳转的公用函数popToNextFragment:

        /**
         * 使用 rxJava 在 UI主线程异步执行定义的具体操作,绑定生命周期了,有效阻止内存泄露
         */
        protected fun executeActions(actions: () -> Unit) {
            Completable.fromAction(actions)
                .subscribeOn(AndroidSchedulers.mainThread())
                .observeOn(AndroidSchedulers.mainThread())
                .bindUntilEvent(this, FragmentEvent.DESTROY)
                .subscribe()
        }
    
    
        /**
         * 跳转到下一个fragment,仅支持 ISupportFragment 的 router,
         * <br/>如果targetRouter指定的目标对象不是ISupportFragment,则不会跳转
         * @param targetRouter 指代要跳转的 目标 fragment 的路由 url,使用的是阿里的 ARouter 框架
         * @param params 传递给下一个 fragment的信息对象,可为 null,在 target Fragment 中使用 args()函数获取
         *
         */
        protected fun popToNextFragment(targetRouter: String, params: Parcelable? = null) {
            executeActions {
                val fragment = ARouter.getInstance().build(targetRouter).withParcelable(MvRx.KEY_ARG, params).navigation()
                if (fragment is ISupportFragment) {
                    start(fragment)
                }
            }
        }

    简单讲解一下 executeActions,此函数为通过 RxJava 异步执行函数在AndroidSchedulers.mainThread()主线程上执行actions: () -> Unit 这个 Closure 闭包函数,无返回值。此函数在很多操作必须在主线程上执行才不发生报错异常上面很有用,比如 UI 赋值响应等等。popToNextFragment用来 fragments 之间的跳转,参数为 Arouter 注解在实例 Fragment 上的注解值,让 Arouter生成 Fragment 实例并赋值 key为MvRx.KEY_ARG的 parcelable 可反序列化对象 extra param,在提取此附加参数时直接调用MvRx 的 args()函数即可。用 Arouter 的作用是解耦实例 fragment 的产生和面向接口 ISupportFragment编程,不需关心具体的实例对象。

  5. (Optional可选项)封装了一个公用的 fragment 栈退出策略函数launchUniversalPopUpStrategy,一个显示既出 APP的弹窗函数showQuitAppDialog。其中launchUniversalPopUpStrategy内部实现采用了工具函数库 AndroidUtilCode的静态方法,并使用了 kotlin 的open关键字表示此方法可 override.showQuitAppDialog中采用了腾讯 QMUI库的代码和Kotlin 的Lambda表达式风格的函数。仅供参考。此代码见 Github.

  6. override 并提供默认的跳转动画,其中查看 Fragmatation库的动画优先级,当 IFragmentSupport 接口提供了动画对象,则优先使用,否则采用 ISupportActivity中提供的。

        override fun onCreateFragmentAnimator(): FragmentAnimator {
            return DefaultHorizontalAnimator()
        }

    参见此库作者的如下优先级调用的源代码即秒懂:

        /**
         * 获取设置的全局动画
         *
         * @return FragmentAnimator
         */
        public FragmentAnimator getFragmentAnimator() {
            if (mSupport == null)
                throw new RuntimeException("Fragment has not been attached to Activity!");
    
            if (mFragmentAnimator == null) {
                mFragmentAnimator = mSupportF.onCreateFragmentAnimator();
                if (mFragmentAnimator == null) {
                    mFragmentAnimator = mSupport.getFragmentAnimator();
                }
            }
            return mFragmentAnimator;
        }

     

  7. 有关 BaseActivity 的封装一个名为 CoreActivity 的类,具体的功能函数与CoreFragment 差不多,不过增加了一个沉浸式状态栏的开关函数makeStatusBarTranslucent(),以及一个滑动退出优先级函数swipeBackPriority和返回键响应函数onBackPressedSupport。

参见后续文章《献给android原生应用层开发初学者技术架构选型和整合的方案思路(六)》,此篇准备讲解一下  ViewModel 的封装、Retrofit2网络访问请求封装API 并与 RxAndoid2/RxJava2的集成、一些请求拦截器链的集成到 Retrofit2的底层 OKHttp3中、Room 库的 ORM的基础组成步骤等等。

上一篇:css-base-ul+背景图片列表


下一篇:BroadCastReceiver有序广播和EventBus