UI給了空數據頁的圖,可是下一個模塊又想換style,某些特殊的界面又要特殊定製,好煩!git
ToolBar的樣式都差很少,可是具體到項目中又時時有所調整,碎片化十分嚴重,怎麼辦?github
BaseActivity 和 BaseFragment 已經膨脹得快炸掉了,還要往裏面加東西?緩存
因此咱們須要一種能夠靈活配置的手段,進能夠全局配置,統一使用,退能夠具體到某個Activity,進行個性化定製,而且除了全局和Activity,咱們還須要更細緻的層級,好比位於全局和Activity之間的Module等等,它們之間遵循某個規律,高權限能夠覆蓋低權限,越細緻的配置越要作更多的事情,而若是僅僅是使用全局配置,就要令其儘量少作事情,權限越大,責任越大。bash
上述一系列的問題均可以用這套組合拳解決部分問題;app
一、對於要配置的屬性抽象成interface,給具體的頁面實現,固然一些非必要配置的屬性能夠利用Java8/Kotlin作默認實現;ide
二、而後在Application.ActivityLifecycleCallbacks
和FragmentManager.FragmentLifecycleCallbacks
中獲取到具體某個頁面要配置的東西,作具體的配置,咱們所說的多級配置的控制也是在這裏去實現;oop
三、最後註冊一個ContentProvider,在onCreate
中獲取到application,而後把上面配置好的Application.ActivityLifecycleCallbacks
註冊進去,而FragmentManager.FragmentLifecycleCallbacks
則是在Application.ActivityLifecycleCallbacks
的onCreate
中註冊。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.ActivityLifecycleCallbacks
和FragmentManager.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
,作特殊配置。
除了上述的3+2以外,咱們也能夠經過全局Map去緩存一些配置,能夠用包名前綴作Key,從而實現按照不一樣的Module配置不一樣的樣式,也能夠經過註解的手段優化開發體驗等等。
最後我也寫了個demo,包括沉浸式配置、空數據頁錯誤頁配置、Loading配置、ToolBar配置,固然,目前還未完善,計劃寫完用在項目中,待項目完結再發個開源吧。