【问题标题】:Get the same instance of ViewModel in Fragment which is defined in Activity with parameter在 Fragment 中获取相同的 ViewModel 实例,该实例在 Activity 中使用参数定义
【发布时间】:2020-02-14 09:12:01
【问题描述】:

所以,我使用Koin 进行依赖注入,这是我在活动中所做的

class ModuleDetailActivity : AppCompatActivity() {

    private lateinit var moduleId:String
    private lateinit var levelModule:Level.Module

    private val moduleViewModel: ModuleViewModel by viewModel { parameterOf(moduleId, levelModule) }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        ...
        ...

        moduleId = intent.getString("module_id")
        levelModule = intent.getParcelable("level_module")

        ...
        ...
    }
}

现在,我有多个片段 ModuleDetailActivity 可以添加或替换,我希望在这些片段中使用相同的 moduleViewModel 实例,而不在 Fragment 中传递任何参数。

class ModuleDetailFragment : Fragment() {

    private val moduleViewModel: ModuleViewModel by sharedViewModel()

    ...
    ...
}

我知道这会抛出一个错误,正如预期的那样,你可以看到这个

Caused by: org.koin.core.error.InstanceCreationException: Could not create instance for [Factory:'****.ui.module.ModuleViewModel']

这就是我初始化模块的方式

val viewModelModule = module {
    viewModel { (id : String, levelModule:Level.Module) -> ModuleViewModel(id, levelModule, get()) }
}

有什么解决方案可以让我在活动内部定义相同的ModuleViewModel 实例而不在Fragment 中传递参数?

【问题讨论】:

    标签: android kotlin viewmodel koin


    【解决方案1】:

    使用 KOIN

    ViewModel 实例可以在 Fragment 及其宿主 Activity 之间共享。

    要在 Fragment 中注入共享 ViewModel,请使用:

    by sharedViewModel() - lazy delegate property to inject shared ViewModel instance into a property
    getSharedViewModel() - directly get the shared ViewModel instance
    

    只需声明一次 ViewModel:

    val weatherAppModule = module {
    
       // WeatherViewModel declaration for Weather View components
       viewModel { WeatherViewModel(get(), get()) }
    
    }
    

    在你的活动中:

    class WeatherActivity : AppCompatActivity() {
    
        /*
         * Declare WeatherViewModel with Koin and allow constructor dependency injection
         */
        private val weatherViewModel by viewModel<WeatherViewModel>()
    }
    

    在您的片段中:

    class WeatherHeaderFragment : Fragment() {
    
        /*
         * Declare shared WeatherViewModel with WeatherActivity
         */
        private val weatherViewModel by sharedViewModel<WeatherViewModel>()
    }
    

    其他片段:

    class WeatherListFragment : Fragment() {
    
        /*
         * Declare shared WeatherViewModel with WeatherActivity
         */
        private val weatherViewModel by sharedViewModel<WeatherViewModel>()
    }
    

    【讨论】:

      【解决方案2】:

      你应该初始化viewModel如下:

      class ModuleDetailActivity : AppCompatActivity() {
      
          private val moduleId: String by lazy {
              intent.getString("module_id")
          }
      
          private val levelModule: Level.Module by lazy {
              intent.getParcelable("level_module")
          }
      
          private val moduleViewModel: ModuleViewModel by viewModel {
              parameterOf(moduleId, levelModule)
          }
      
          override fun onCreate(savedInstanceState: Bundle?) {
              super.onCreate(savedInstanceState)
      
              ...
              ...
      
              viewModel.doYourStuff()
      
              ...
              ...
          }
      }
      

      我们应该只对纯 Java 对象使用 get()inject()。为了注入ViewModel,他们提供了单独的方式viewModel()

      不知道为什么它不适合你。

      【讨论】:

      • 我已经更新了问题并添加了一些我错过的细节。我知道我可以使用viewModel 获得ViewModel 实例。但我想要的是相同的实例,如果在活动中定义,在没有参数的片段中使用参数。
      • 兄弟,我知道如何在Activity 中定义ViewModel有没有一种方法可以在片段中获得相同的视图模型,而无需传递我在 Activity 中已经完成的参数?
      • @Hussain 我用的和你一样。不知道为什么它不适合你。我已经分享了我的工作示例中的代码。
      • 您只提到了活动部分。如何在片段中做到这一点?而且我不想在片段中传递相同的参数。
      • @Hussain Fragment 部分是正确的,和我实现的一样。
      猜你喜欢
      • 2016-07-19
      • 1970-01-01
      • 2023-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-07
      • 1970-01-01
      相关资源
      最近更新 更多