【问题标题】:How do I pass an argument to the view model?如何将参数传递给视图模型?
【发布时间】:2021-06-30 09:14:15
【问题描述】:

我需要从片段内的参数中获取参数并将其提供给视图模型,以便它根据它过滤列表或不过滤。我认为可以将此参数传递给视图模型的工厂,然后从那里传递给视图模型本身的构造函数,因此它将具有 val onlyFavorites 并且可以立即在 init 块中使用。

ContentFragment.kt

class ContentFragment : Fragment(), ItemFavoriteClickListener {

    private val viewModel: ContentViewModel by viewModels(factoryProducer = {
        ContentViewModel.Factory()
    })

    private var adapter: MyItemModelsAdapter? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        arguments?.getBoolean("onlyFavorites", false)
        
        viewModel.items.observe(this) {
            adapter?.items = it
        }
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        recyclerView?.layoutManager = LinearLayoutManager(context)

        adapter = MyItemModelsAdapter(this)
        recyclerView?.adapter = adapter
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_favourites, container, false)
    }

    override fun onFavoriteClick(item: ItemModel, isFavorite: Boolean) {
        viewModel.changeFavoriteState(item, isFavorite)
    }

    companion object {
        fun newInstance(onlyFavorites: Boolean): ContentFragment {
            val contentFragment = ContentFragment()
            val args = Bundle()
            args.putBoolean("onlyFavorites", onlyFavorites)
            contentFragment.arguments = args

            return contentFragment
        }
    }
}

ContentViewModel.kt

class ContentViewModel(
    private val repository: MyItemsRepository
) : ViewModel() {

    class Factory : ViewModelProvider.Factory {
        override fun <T : ViewModel?> create(modelClass: Class<T>): T {
            return ContentViewModel(MyItemsRepositoryImpl.getInstance()) as T
        }
    }

    private val _items: MutableLiveData<List<ItemModel>> = MutableLiveData()
    val items: LiveData<List<ItemModel>>
        get() = _items

    fun changeFavoriteState(item: ItemModel, favorite: Boolean) {
        repository.setFavorite(item, favorite)
    }

    init {
        _items.value = repository.items.filter { it.isFavorite }
        repository.addItemChangeListener {
            _items.value = repository.items.filter { it.isFavorite }
        }
    }
}

我需要您的帮助来编写代码。我心里明白怎么做,但我不知道怎么写。非常感谢您提供带有解释的书面示例。

【问题讨论】:

    标签: android kotlin viewmodel factory


    【解决方案1】:

    这并不像看起来那么难;只需在 ContentViewModel 中创建一个新的公共变量

    var isFavorite: Boolean = false

    然后代替 ViewModel 的 init,将您的获取逻辑放在一个方法中。

    fun getItems() {
        _items.value = repository.items.filter { it.isFavorite == isFavorite }
    }
    

    现在在片段的 onViewCreated() 中调用这个方法,如下所示:

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        recyclerView?.layoutManager = LinearLayoutManager(context)
    
        adapter = MyItemModelsAdapter(this)
        recyclerView?.adapter = adapter
    
        val isFavorite = arguments?.getBoolean("onlyFavorites", false) ?: false
        viewModel.isFavorite = isFavorite
    
        viewModel.getItems()
        
        viewModel.items.observe(this) {
            adapter?.items = it
        }
    }
    

    这样,在实际调用 getItems 方法之前,您就拥有了 isFavorite 的值。

    我还没有测试过这段代码,但我很确定它会起作用。

    如果您需要更多帮助,请发表评论。

    【讨论】:

    • 非常感谢。但我有一些麻烦。第一个是在行 viewModel.isFavorite = isFavorite(Type mismatch.Required:Boolean Found:Boolean?),第二个是 viewModel.items.observe(this) { adapter?.items = it } 。 "this" - 使用 viewLifecycleOwner 作为 LifecycleOwner。你能告诉我如何解决它吗?
    • 我编辑了答案,基本上,那个错误是说你试图将一个可为空的值分配给一个非空值。在此处了解有关 Kotlin 空安全性的更多信息:journaldev.com/17568/kotlin-null-safety-nullable
    • 很好,几乎所有东西都能正常运行。
    • 没问题。顺便说一句,我认为在 onCreate 方法中为片段编写代码会更好。事实上,onViewCreated 方法的调用频率要比 onCreate 高得多,因此最好在 onCreate 方法中调用初始数据加载。
    • 是的,这是有道理的,但要小心,不要在 onCreate 中做任何 UI 操作,因为视图尚未膨胀。无论如何onViewCreated 不会被再次调用,除非片段需要重新创建自己。所以使用onViewCreated 也是安全的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-08-10
    • 2018-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-09
    • 1970-01-01
    相关资源
    最近更新 更多