我有一个ViewModel处理我的业务逻辑,我正在使用Koin将它注入到我的活动和每个片段中。然而,在我从片段A-片段B导航并导航回片段A之后,我的观察者再次被触发。为什么会发生这种情况?当我返回时,如何阻止这种onChanged被触发?
我尝试将'this'和'view LifecycleOwner'设置为LiveData的LifecycleOwner。
我还尝试将observable移动到onCreate、onActivityCreated和onViewCreated
class MyViewModel : ViewModel() {
private val _myData = MutableLiveData<Data>()
val myData = LiveData<Data>()
get() = _myData
fun doSomething() {
... // some code
_myData.postValue(myResult)
}
class Activity : BaseActivity() {
private val viewModel by viewModel<MyViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_login)
setSupportActionBar(main_toolbar)
subscribeUI()
}
private fun subscribeUI() {
myViewModel.isLoading.observe(this, Observer {
toggleProgress(it)
})
}
}
class FragmentA : BaseFragment() {
private val viewModel by sharedViewModel<MyViewModel>()
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
subscribeUI()
}
private fun subscribeUI() {
viewModel.myData.observe(viewLifecycleOwner, Observer {
val direction =
FragmentADirections.actionAtoB()
mainNavController?.navigate(direction)
})
}
}
class FragmentB : BaseFragment() {
private val authViewModel by sharedViewModel<LoginViewModel>()
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
subscribeUI()
}
private fun subscribeUI() {
viewModel.otherData.observe(viewLifecycleOwner, Observer {
// Do something else...
})
}
}
这是使用MutableLiveData
时的预期行为。我认为你的问题与在哪里添加或删除订阅者无关。
MutableLiveData
保存设置它的最后一个值。当我们回到前一个片段时,我们的LiveData
观察再次收到现有值的通知。这是为了保留片段的状态,这正是LiveData
的确切目的。
谷歌自己已经解决了这个问题,并提供了一种方法来克服这种行为,那就是使用事件包装器。
/**
* Used as a wrapper for data that is exposed via a LiveData that represents an event.
*/
open class Event<out T>(private val content: T) {
var hasBeenHandled = false
private set // Allow external read but not write
/**
* Returns the content and prevents its use again.
*/
fun getContentIfNotHandled(): T? {
return if (hasBeenHandled) {
null
} else {
hasBeenHandled = true
content
}
}
/**
* Returns the content, even if it's already been handled.
*/
fun peekContent(): T = content
}
class EventObserver<T>(private val onEventUnhandledContent: (T) -> Unit) : Observer<Event<T>> {
override fun onChanged(event: Event<T>?) {
event?.getContentIfNotHandled()?.let { value ->
onEventUnhandledContent(value)
}
}
}
// Declare live data object
val testLiveData: MutableLiveData<Event<Boolean>
by lazy{ MutableLiveData<Event<Boolean>>() }
testLiveData.postValue(Event(true))
viewModel?.testLiveData?.observe(this, EventObserver { result ->
// Your actions
}
这里是链接的代码,我正在做同样的事情链接
我正试着从后面取回碎片。它正在被检索,但问题是在按下后退按钮时,当前片段的oncreate视图和后续lifecyce方法也会被调用。下面是我将片段放入backbackback的代码: 以下是片段的代码:
我正在使用registerForActivityResult,因为StartActivityForResult函数已被弃用。因此,我们正朝着使用registerForActivityResult的新方式迁移。这在活动中非常有效。然而,当在片段中使用这个函数时,永远不会调用回调函数。我还必须提到,父活动和其他子片段以旧的方式处理一些结果。调试代码时,我看到调用了父级的onActivityResult
我有一个ViewPagerContainer片段,在应用程序启动时加载。ViewPagerContainer片段将两个选项卡(选项卡A和选项卡B)添加到操作栏。选项卡B有两个项目的列表视图。 我所做的:我在选项卡B片段中的列表视图项上附加了一个click listener,这样当用户单击一个项时,它会在第一个片段(即选项卡B下)内打开另一个片段(子片段)。 我陷入困境的地方:当用户按下后退按钮时,
当我使用底部导航进行导航时,碎片会被破坏,计时器会重置到00:00。我用过计时器。我尝试了RetainInstance=true,但它只在屏幕旋转时才有帮助。 mainactivity.kt TimerFragment.kt
我的应用程序有两个项目的导航抽屉:一个ViewPager(在一个片段内)和支持Map碎片。 ViewPager使用FragmentStatePagerAdapter并返回两个片段。 当我打开抽屉菜单并选择“项目1”(支持MapFrature)时,另一个碎片(ViewPager在其中)执行,但此方法不会破坏适配器创建的碎片,所以当我再次选择“项目0”时,我的应用程序创建的ViewPager与它的两个