MVVM // 在 Activity 旋转时触发 ViewModel 事件(重新创建)
Posted
技术标签:
【中文标题】MVVM // 在 Activity 旋转时触发 ViewModel 事件(重新创建)【英文标题】:MVVM // ViewModel event being fired on Activity rotation (recreated) 【发布时间】:2017-11-05 00:10:05 【问题描述】:阅读Google docs,我发现(有点)一个使用selectedItem
的示例,以便将触发的事件传播给其他观察者,这是我当前的实现:
视图模型
public void onListItemClicked(Item item)
if (selectedItem.getValue() == item)
return;
selectedItem.postValue(item);
public LiveData<Item> getSelectedItem()
if (selectedItem == null)
selectedItem = new MutableLiveData<>();
return selectedItem;
查看
ListViewModel viewModel = ViewModelProviders.of(this).get(ListViewModel.class);
viewModel.getSelectedItem().observe(this, new Observer<Item>()
@Override
public void onChanged(@Nullable Item item)
if (item != null)
openDetailActivity(item);
);
当用户点击列表时:
@Override
public void onItemClicked(Item item)
viewModel.onListItemClicked(item);
所有一切正常,问题是当用户旋转屏幕并重新创建ListActivity
时检测到更改并打开@ 987654327@订阅时。
我找到了一种解决方法,即在 getSelectedItem()
上添加 selectedItem.postValue(null);
,但这有点笨拙。
有人可能会争辩说,打开细节活动和传播事件应该是分开的,但我想知道是否有人有更好的实施/建议。
【问题讨论】:
【参考方案1】:编辑
使用SingleLiveEvent
是可行的方法。这可以确保您的 ViewModel
只触发一次事件。
这是参考文章:
LiveData with SnackBar, Navigation and other events (the SingleLiveEvent case)
Java类可以在文章中找到
我用Kotlin
类创建了一个要点。
我一直在成功地使用这些用例:
Always up-to-date gist SingleLiveEvent.kt
我会及时更新要点,但我也会在此处保留代码 (仅供参考,这可能已经过时,因为我不会在每次更改要点时都编辑此答案):
package YOUR_PACKAGE
import androidx.annotation.MainThread
import androidx.annotation.Nullable
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import java.util.concurrent.atomic.AtomicBoolean
/**
* A lifecycle-aware observable that sends only new updates after subscription, used for events like
* navigation and Snackbar messages.
* <p>
* This avoids a common problem with events: on configuration change (like rotation) an update
* can be emitted if the observer is active. This LiveData only calls the observable if there's an
* explicit call to setValue() or call().
* <p>
* Note that only one observer is going to be notified of changes.
*/
class SingleLiveEvent<T> : MutableLiveData<T>()
private val mPending = AtomicBoolean(false)
@MainThread
override fun observe(owner: LifecycleOwner, observer: Observer<in T>)
// Observe the internal MutableLiveData
super.observe(owner, Observer<T> t ->
if (mPending.compareAndSet(true, false))
observer.onChanged(t)
)
@MainThread
override fun setValue(@Nullable t: T?)
mPending.set(true)
super.setValue(t)
/**
* Used for cases where T is Void, to make calls cleaner.
*/
@MainThread
fun call()
value = null
旧答案:
所以在进行了大量研究并与 Google 开发人员取得联系后。推荐的解决方案是有单独的职责。
如果响应点击事件而不是实际更改,则打开活动,这种类型的selectedItem
场景对于解耦通信与其他侦听视图特别有用。
例如同一活动中的另一个片段
【讨论】:
以上是关于MVVM // 在 Activity 旋转时触发 ViewModel 事件(重新创建)的主要内容,如果未能解决你的问题,请参考以下文章
在 Android 上使用 MVVM 时,每个 Activity 是不是应该有一个(且只有一个)ViewModel?