Android LiveData - 如何在不同的活动中重用同一个 ViewModel?

Android LiveData - how to reuse the same ViewModel on different activities?

示例视图模型:

public class NameViewModel extends ViewModel {
    // Create a LiveData with a String
    private MutableLiveData<String> mCurrentName;

    public MutableLiveData<String> getCurrentName() {
        if (mCurrentName == null) {
            mCurrentName = new MutableLiveData<>();
        }
        return mCurrentName;
    }

}

主要activity:

mModel = ViewModelProviders.of(this).get(NameViewModel.class);

// Create the observer which updates the UI.
final Observer<String> nameObserver = textView::setText;

// Observe the LiveData, passing in this activity as the LifecycleOwner and the observer.
mModel.getCurrentName().observe(this, nameObserver);

我想在第二个 activity 中调用 mModel.getCurrentName().setValue(anotherName); 并使 MainActivity 接收更改。这可能吗?

当你调用 ViewModelProviders.of(this) 时,你实际上 create/retain 一个绑定到 thisViewModelStore,所以不同的 Activity 有不同的 ViewModelStore 并且每个 ViewModelStore 使用给定的工厂创建 ViewModel 的不同实例,因此您不能在不同的 ViewModelStore 中拥有相同的 ViewModel 实例。

但是您可以通过传递充当单例工厂的自定义 ViewModel 工厂的单个实例来实现此目的,因此它将始终在不同的活动之间传递 ViewModel 的相同实例。

例如:

public class SingletonNameViewModelFactory extends ViewModelProvider.NewInstanceFactory {


    NameViewModel t;

    public SingletonNameViewModelFactory() {
      //  t = provideNameViewModelSomeHowUsingDependencyInjection
    }

    @Override
    public NameViewModel create(Class<NameViewModel> modelClass) {
        return t;
    }
}

所以你需要制作 SingletonNameViewModelFactory 单例(例如使用 Dagger)并像这样使用它:

mModel = ViewModelProviders.of(this,myFactory).get(NameViewModel.class);

注:

在不同范围之间保留 ViewModels 是 anti-pattern。强烈建议保留您的 data-layer 对象(例如,使您的数据源或存储库单例)并在不同范围(活动)之间保留您的数据。

阅读 this 文章了解详情。

当使用您作为生命周期所有者传递给 MainActivity 的 ViewModelProvider 获取视图模型时,这将为 activity 提供视图模型。在第二个 activity 中,您将获得该 ViewModel 的另一个实例,这次是您的第二个 Activity。第二个模型将有第二个实时数据。

你可以做的是在不同的层维护数据,比如存储库,它可能是一个单例,这样你就可以使用相同的视图模型。

public class NameViewModel extends ViewModel {
    // Create a LiveData with a String
    private MutableLiveData<String> mCurrentName;

    public MutableLiveData<String> getCurrentName() {
        if (mCurrentName == null) {
            mCurrentName = DataRepository.getInstance().getCurrentName();
        }
        return mCurrentName;
    }
}

//SingleTon
public class DataRepository     

    private MutableLiveData<String> mCurrentName;

    public MutableLiveData<String> getCurrentName() {
        if (mCurrentName == null) {
            mCurrentName = new MutableLiveData<>();
        }
        return mCurrentName;
    }
//Singleton code
...
}

只需创建 ViewModel 的实例,在本例中为 NameViewModel

你的 ViewModel 工厂就像

class ViewModelFactory : ViewModelProvider.NewInstanceFactory() {

    override fun <T : ViewModel?> create(modelClass: Class<T>) =
        with(modelClass){
            when {
                isAssignableFrom(NameViewModel::class.java) -> NameViewModel.getInstance()
                else -> throw IllegalArgumentException("Unknown viewModel class $modelClass")
            }
        } as T


    companion object {
        private var instance : ViewModelFactory? = null
        fun getInstance() =
            instance ?: synchronized(ViewModelFactory::class.java){
                instance ?: ViewModelFactory().also { instance = it }
            }
    }
}

还有你的 ViewModel

class NameViewModel : ViewModel() {

    //your liveData objects and many more...

    companion object {
        private var instance : NameViewModel? = null
        fun getInstance() =
            instance ?: synchronized(NameViewModel::class.java){
                instance ?: NameViewModel().also { instance = it }
            }
    }
}

现在您可以使用 ViewModelProviders 获取相同的 ViewModel 实例以在任何 activity

中使用
ViewModelProviders.of(this, ViewModelFactory.getInstance()).get(NameViewModel::class.java)

创建一个扩展函数以便于访问

fun <T : ViewModel> AppCompatActivity.getViewModel(viewModelClass: Class<T>) =
    ViewModelProviders.of(this, ViewModelFactory.getInstance()).get(viewModelClass)

ViewModel scope/lifecycle 与 activity 绑定只是因为您传递给 ViewModelProvider 构造函数的 ViewModelStoreOwner 恰好是 activity.

由于您要提供 ViewModelStoreOwner,因此您可以轻松地提供一个具有更长生命周期的对象,例如应用程序。

你可以

  1. 提供您自己的 Application 子类并使其实现 ViewModelStoreOwner(并拥有一个 ViewModelStore)
  2. 在 ViewModelProvider 构造函数调用中,传递 activity.application 而不是 activity。

这将导致 ViewModelProvider 与 application-level ViewModelStore 交互,允许您创建具有应用程序范围的 ViewModel 实例。