【问题标题】:How do I use the new Saved State Module of ViewModel如何使用 ViewModel 的新保存状态模块
【发布时间】:2020-01-11 20:47:02
【问题描述】:

我正在使用生命周期版本 2.2.0-rc03 和 official docs,发现的文章甚至没有列出正确的类名或构造函数参数。我想我必须通过这样的方式获取 ViewModel 实例

viewModel = ViewModelProvider(this, SavedStateViewModelFactory(requireActivity().application, savedStateRegistryOwner))
            .get(SelectedTracksViewModel::class.java)

但我不知道 SavedStateRegistryOwner。

有人可以举一个简单的例子来说明如何创建已保存状态的 ViewModel 实例以及在 ViewModel 中保存和恢复值的正确方法吗?

【问题讨论】:

    标签: android android-viewmodel android-savedstate


    【解决方案1】:

    要为 View Model 使用 Saved State 模块,您必须将 androidx.lifecycle:lifecycle-viewmodel-savedstate 依赖项添加到您的项目中。本示例基于1.0.0-rc03版本编写。

    请在您的项目 Gradle 文件中添加以下行:
    implementation 'androidx.lifecycle:lifecycle-viewmodel-savedstate:1.0.0-rc03'

    ViewModel 实现:

    class SavedStateViewModel(private val state: SavedStateHandle) : ViewModel() {
    
        val liveData = state.getLiveData("liveData", Random.nextInt().toString())
    
        fun saveState() {
            state.set("liveData", liveData.value)
        }
    }
    

    活动实施:

    class SavedStateActivity : AppCompatActivity() {
    
        lateinit var viewModel: SavedStateViewModel;
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            val binding: ActivityStateBinding = DataBindingUtil.setContentView(this, R.layout.activity_state)
    
            viewModel = ViewModelProvider(this, SavedStateViewModelFactory(this.application, this)).get(SavedStateViewModel::class.java)
    
            binding.viewModel = viewModel
            binding.lifecycleOwner = this
        }
    
        override fun onSaveInstanceState(outState: Bundle) {
            if(::viewModel.isInitialized)
                viewModel.saveState()
    
            super.onSaveInstanceState(outState)
        }
    }
    

    我已经测试了这段代码,它工作正常。

    【讨论】:

    • 如果您已经获得savedStateHandle.getLiveData的LiveData,则无需手动设置onSaveInstanceState的实时数据密钥。
    • @EpicPandaForce 我评论了state.set("liveData", liveDate.value) 行并使用lifecycle-viewmodel-savedstate 2.2.0 版进行了测试,但不幸的是它对我不起作用。能否提供工作示例代码?
    • 从技术上讲,如果您使用 savedStateHandle.getLiveData,则完全不需要您的 saveState 方法
    • super.onSaveInstanceState(outState)之前调用viewModel.saveState()很重要,否则由于我还不知道的某些原因它不起作用
    • 很抱歉,我不能同意这一点。 (也许只是有点太晚了)。 VM 保存的状态已经是生命周期感知的。您无需将视图 LifeCycle 附加到它们已经存在的 VM。
    【解决方案2】:

    我正在为这个旧帖子添加一个答案,以防有人发现它有用。

    我设法做到了如下:

    • 将以下依赖项添加到您的“build.gradle (Module: app)”文件中
    implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
    
    • savedState: SavedStateHandle 属性添加到ViewModel 的构造函数中
    class SelectedTracksViewModel(private val savedState: SavedStateHandle) : ViewModel() {
    
        companion object {
            private const val SAVED_TRACK_INDEX = "savedTrackIndex"
        }
    
        private var trackIndex: Int
          set(value) {
            field = value
            // Simply update the savedState every time your saved property changes
            savedState.set(SAVED_TRACK_INDEX, value)
          }
    
        init {
            trackIndex = savedState.get<Int>(SAVED_TRACK_INDEX) ?: 0
        }
    
        fun moveToNextTrack() {
            trackIndex++ 
            // Initially I was updating savedState here - now moved to setter
            
            // Some more code here
        }    
    }
    

    终于在活动/片段中

        private val selectedTracksViewModel: SelectedTracksViewModel by lazy {
            ViewModelProvider(this).get(SelectedTracksViewModel::class.java)
        }
    

    就是这样。不需要SavedStateViewModelFactory,只需将savedState 属性添加到ViewModel 构造函数中,并在跟踪的属性更改时更新它。其他一切都好像您没有使用 savedState: SavedStateHandle 一样工作,这种方式与活动/片段中的传统 onSaveInstanceState(Bundle) 非常相似。

    更新:最初我在更改trackIndex 后更新savedState。这意味着必须更新savedState每次保存的属性被更改。如果忘记添加该行,这将是一个巨大的潜在错误。更好更健壮的模式是更新属性设置器中的savedState

    【讨论】:

      【解决方案3】:

      据我了解,您想使用规范构造函数创建视图模型。 你可以使用ViewModelProvider.Factory

      viewModel = ViewModelProvider(this, SavedStateViewModelFactory.create(state)
                  .get(SelectedTracksViewModel::class.java)
      

      ViewModelFactory 示例

      public class SavedStateViewModelFactory {
      
          public static <E> ViewModelProvider.Factory create(State state){
      
              return new ViewModelProvider.Factory() {
                  @NonNull
                  @Override
                  @SuppressWarnings("unchecked")
                  public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
                      if (modelClass.isAssignableFrom(SelectedTracksViewModel.class)) {
                          return (T) new SelectedTracksViewModel<>(state);
                      } else {
                          throw new IllegalArgumentException("Unknown ViewModel class");
                      }
                  }
              };
          }
      
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-09-20
        • 2019-07-17
        • 2010-10-01
        • 2010-09-14
        • 1970-01-01
        • 1970-01-01
        • 2014-02-15
        相关资源
        最近更新 更多