大家好,本篇文章给大家分享下官方开源库activity-ktx提供的几个有用的小工具,希望能对你有所帮助,本篇文章为大家带来ComponentDialog
的介绍。
当前基于如下版本进行分析:
groovy
dependencies {
implementation "androidx.activity:activity-ktx:1.8.0"
}
ComponentDialog---集各种特性于一体的大成Dialog
如果经常使用Android Jetpack相关组件的开发者,相信对下面的几个接口非常了解:
LifecycleOwner
:提供组件可观察的生命周期OnBackPressedDispatcherOwner
:提供系统返回按钮事件的监听;SavedStateRegistryOwner
:保存因配置发生更改界面销毁重建前的相关数据,重建后能够重新获取
借助于官方的支持,上面这些接口特性在Activity
、Fragment
中都有体现,但是大家想一想,Dialog
有这个待遇吗?哈哈,这不ComponentDialog
组件就应运而生了。
kotlin
open class ComponentDialog @JvmOverloads constructor(
context: Context,
@StyleRes themeResId: Int = 0
) : Dialog(context, themeResId),
LifecycleOwner,
OnBackPressedDispatcherOwner,
SavedStateRegistryOwner {
//...
}
ComponentDialog实现了上面的三个接口,所以拥有了三个接口对应的能力,接下来咱们来分别演示下。
先自定义一个ComponentDialog类:
kotlin
class CustomComponentDialog(mContext: Context): ComponentDialog(mContext) {
override fun onSaveInstanceState(): Bundle {
return super.onSaveInstanceState()
}
}
1. LifecycleOwner能力
kotlin
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val customComponentDialog = CustomComponentDialog(this)
customComponentDialog.show()
customComponentDialog.lifecycle.addObserver(object : DefaultLifecycleObserver {
override fun onCreate(owner: LifecycleOwner) {
super.onCreate(owner)
}
override fun onResume(owner: LifecycleOwner) {
super.onResume(owner)
}
override fun onDestroy(owner: LifecycleOwner) {
super.onDestroy(owner)
}
})
}
如果是我们直接之前使用Dialog,为了监听Dialog的show和dismiss等场景,都会主动调用方法诸如setOnDismissListener
和setOnShowListener
等设置监听器,这样就会导致一个安全隐患:Dialog持有了外部类引用,而这个外部类引用会被对象池中的Message持有,如果这个Message和HanderThread消息队列中的Message共享,那这就产生内存泄漏的安全隐患。DialogFragment也同样存在这样的安全隐患。
这个内存泄漏的安全隐患就不再这里进行分析了,大家可以这两篇文章了解学习一番:
Android开发:Message 引发的 DialogFragment 内存泄漏分析与解决方案
而现在ComponentDialog提供了Lifecycle的能力,我们就可以通过添加观察者的方式来监听Dialog的show和dismiss,而不会产生丝毫内存泄漏的安全隐患,大家可以放心食用。
不过这里有两点需要注意的地方:
-
lifecycle的resume方法执行是早于监听器
setOnShowListener(DialogInterface.OnShowListener)
回调时机,其借助ComponentDialog#onStart()
方法通知观察者Resume事件发生 -
lifecycle的destory方法执行同样早于监听器
setOnDismissListener(DialogInterface#OnDismissListener)
回调时机,其借助ComponentDialog#onStop
通知观察者onDestory事件产生
2. OnBackPressedDispatcherOwner能力
提供监听系统返回按键点击事件的能力
arduino
customComponentDialog.onBackPressedDispatcher.addCallback {
Log.i("TAG", "onCreate: onBackPressedDispatcher")
isEnable = false
}
不过这个工具可要善用,比如如果上面代码中没有关键的isEnable = false
,那么相当于系统返回按钮事件就被这个Dialog给拦截了,其他的地方back事件都无法响应了。
所以当处理完Dialog的back监听事件后,需要主动设置isEnable = false
才能保证该系统返回键点击事件能够正常流转,当然了具体要视业务场景而定。
具体的应用场景也会有不少,比如当前正在显示一个提供编辑能力的Dialog,先设置个onBack监听,在点击系统返回键时,提示用户是否要保存草稿等类似功能。相比较直接重写onKeyUp、onBackPress等系统方法,设置onBackPressedCallback的方式使用起来更加灵活方便。
顺便给大家推荐一个好用的扩展方法,这样添加onback监听就十分方便了:
3. SavedStateRegistryOwner能力
这个类似于有点类似于ViewModel,能够保存状态数据,比如当界面由于旋转、换肤等此原因导致Activity重建时,就可以将之前的数据进行重现,和ViewModel的能力有点像。
scss
customComponentDialog.savedStateRegistry.registerSavedStateProvider("key") {
Bundle().apply {
putInt("count", 100)
}
}
指定一个key,以及要存储的数据即可,最终这个伴随着Dialog#onSaveInstanceState()
一起存储。
不过这个作用感觉使用场景不大,而且存在使用限制,而且Dialog依赖Activity的context,直接使用Activity的ViewModel保存数据也能实现Dialog状态数据的保存以及恢复。
当然了仁者见仁,智者见智,对于Dialog使用的这个特性再这里就不再提了。
历史文章
一文洞彻:Application为啥不能作为Dialog的context?
这篇文章大家可以看看哈,也是使用Dialog时需要了解的一个知识点,带你了解Dialog的context一定不能是Application吗?只能是Activity吗?