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配置,固然,目前还未完善,计划写完用在项目中,待项目完结再发个开源吧。