MVVM //在Activity旋转上触发的ViewModel事件(重新创建)

时间:2017-06-03 20:27:26

标签: android mvvm architecture components lifecycle

阅读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检测到更改并将打开订阅时DetailActivity

我找到了一个解决方法,即在selectedItem.postValue(null);上添加getSelectedItem(),但它有点笨拙。

Ofc有人可能会争辩说,开放细节活动和宣传甚至应该是分开的,但我想知道是否有人有更好的实施/建议。

1 个答案:

答案 0 :(得分:1)

修改

使用SingleLiveEvent是可行的方法。这可确保您的ViewModel仅触发一次事件。

以下是参考文章:

我已经用Kotlin课程创建了一个要点。 我一直在成功使用这些用例:

我会保持最新的要点,但我也会将代码保留在这里 (仅供参考,这可能已经过时,因为每次我改变主旨时我都不会编辑这个答案):


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开发者保持联系。建议的解决方案是分别负责。 打开活动应该是对click事件的响应而不是实际更改,这种类型的selectedItem场景对于解耦通信与其他侦听视图特别有用。 例如同一活动中的另一个片段