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/…

相關文章
相關標籤/搜索