Android UI 架构-经常使用的多级配置

UI给了空数据页的图,可是下一个模块又想换style,某些特殊的界面又要特殊定制,好烦!git

ToolBar的样式都差很少,可是具体到项目中又时时有所调整,碎片化十分严重,怎么办?github

BaseActivity 和 BaseFragment 已经膨胀得快炸掉了,还要往里面加东西?缓存

因此咱们须要一种能够灵活配置的手段,进能够全局配置,统一使用,退能够具体到某个Activity,进行个性化定制,而且除了全局Activity,咱们还须要更细致的层级,好比位于全局Activity之间的Module等等,它们之间遵循某个规律,高权限能够覆盖低权限,越细致的配置越要作更多的事情,而若是仅仅是使用全局配置,就要令其尽量少作事情,权限越大,责任越大。bash

用interface作配置,Lifecycle作切面,ContentProvider作初始化

上述一系列的问题均可以用这套组合拳解决部分问题;app

一、对于要配置的属性抽象成interface,给具体的页面实现,固然一些非必要配置的属性能够利用Java8/Kotlin作默认实现;ide

二、而后在Application.ActivityLifecycleCallbacksFragmentManager.FragmentLifecycleCallbacks中获取到具体某个页面要配置的东西,作具体的配置,咱们所说的多级配置的控制也是在这里去实现;oop

三、最后注册一个ContentProvider,在onCreate中获取到application,而后把上面配置好的Application.ActivityLifecycleCallbacks注册进去,而FragmentManager.FragmentLifecycleCallbacks则是在Application.ActivityLifecycleCallbacksonCreate中注册。post

说完理论咱们来举个例子吧,好比ToolBar:优化

一、咱们配置三个接口,默认是ToolBarUI是三段式的:ui

/**
 * 提供给单个Class作特殊配置,最大程度实现灵活配置
 */
interface IInitToolBar {
    fun initToolBar(toolBar: IToolBar?)
}
/**
 * 控制单个Class是否初始化的开关
 */
interface IIsInitToolBar {
    fun initToolBar():Boolean
}
/**
 * ToolBar的具体属性抽象
 */
interface IToolBar {
    fun leftText(): Int? = null
    fun rightText(): Int? = null
    fun leftIcon(): Int? = null
    fun rightIcon(): Int? = null
    fun titleText(): Int? = null
    /**
     * 单位:像素
     */
    fun drawablePadding():Int?=null
    /**
     * 返回true表明被消费
     */
    fun onClickLeft(view: View) = false

    /**
     * 返回true表明被消费
     */
    fun onClickRight(view: View) = false

    /**
     * 初始化而且隐藏
     */
    fun hideToolBar() = false
}
复制代码

二、提供具体的Application.ActivityLifecycleCallbacksFragmentManager.FragmentLifecycleCallbacks实现:

class ToolBarActivityLifecycleCallbacksImpl :
    DefaultActivityLifecycleCallbacks {

    companion object {
        private val handler = Handler(Looper.getMainLooper())
    }

    override fun onActivityCreated(activity: Activity?, savedInstanceState: Bundle?) {
        activity?.let {
            handler.post {
                /**
                 * 可能会用到toolBar,因此丢到队尾执行,确保initView完成
                 */
                ToolBarManager.initToolBar(it as? IToolBar)
            }
        }
        (activity as? FragmentActivity)?.supportFragmentManager?.registerFragmentLifecycleCallbacks(
            ToolBarFragmentLifecycleCallbacksImpl(),
            true
        )
    }
}

class ToolBarFragmentLifecycleCallbacksImpl : FragmentManager.FragmentLifecycleCallbacks() {
    companion object {
        private val handler = Handler(Looper.getMainLooper())
    }

    override fun onFragmentActivityCreated(
        fm: FragmentManager,
        f: Fragment,
        savedInstanceState: Bundle?
    ) {
        handler.post {
            /**
             * 可能会用到toolBar,因此丢到队尾执行,确保initView完成
             */
            ToolBarManager.initToolBar(f as? IToolBar)
        }
    }
}
复制代码

三、用ContentProvider初始化能够把初始化工做交给lib实现,不须要在业务工程中手动注册:

class InitProvider : ContentProvider() {

    override fun onCreate(): Boolean {
        (context?.applicationContext as Application).apply {
            registerActivityLifecycleCallbacks(ToolBarActivityLifecycleCallbacksImpl())
        }
        return true
    }
    ...
复制代码

三级控制+两级配置(级别越大,权限越高)

不难发现,上述配置的具体工做是交由ToolBarManager来完成,文章标题所谓的多级配置也是在这里完成的,咱们看一下具体实现:

override fun initToolBar(toolBar: IToolBar?) {
        //一级控制,全局控制
        var isInitToolBar = defaultIsToolBar
        //二级控制,Class控制
        if (toolBar is IIsInitToolBar) {
            isInitToolBar = toolBar.initToolBar()
        }
        /**
         * 三级控制,Object控制
         */
        isInitToolBar = when (toolBar) {
            is Activity -> {
                toolBar.intent.getBooleanExtra(EXTRA_INIT_TOOLBAR, isInitToolBar).apply {
                    //用完就遗弃,避免脏数据
                    toolBar.intent.removeExtra(EXTRA_INIT_TOOLBAR)
                }
            }
            is Fragment -> {
                toolBar.arguments?.getBoolean(EXTRA_INIT_TOOLBAR, isInitToolBar)?.apply {
                    //用完就遗弃,避免脏数据
                    toolBar.arguments?.remove(EXTRA_INIT_TOOLBAR)
                } ?: isInitToolBar
            }
            else -> {
                isInitToolBar
            }
        }

        if (isInitToolBar) {
            if (toolBar is IInitToolBar) {
                //二级控制,class控制
                toolBar.initToolBar(toolBar)
            } else {
                //一级控制,全局
                defaultInitToolBar.initToolBar(toolBar)
            }
        }

    }
复制代码

ToolBarManager是个单例,defaultIsToolBar就是能够全局更改的字段,它表明权限最低的全局开关;

IIsInitToolBar只作一件事,那就是开关,它表明权限更高的Class开关;

经过intent/arguments来传递的是最高权限的Object开关,不过用完记得移除脏数据。

具体配置的时候,若是该页面的UI符合三段式UI,那么就沿用全局配置的defaultInitToolBar,不然也能够具体界面实现IInitToolBar,作特殊配置。

根据包名的Module级别

除了上述的3+2以外,咱们也能够经过全局Map去缓存一些配置,能够用包名前缀作Key,从而实现按照不一样的Module配置不一样的样式,也能够经过注解的手段优化开发体验等等。

最后我也写了个demo,包括沉浸式配置、空数据页错误页配置、Loading配置、ToolBar配置,固然,目前还未完善,计划写完用在项目中,待项目完结再发个开源吧。

项目地址:github.com/chinwetang/…

相关文章
相关标签/搜索