Optimizing Parent Fragment for ViewModel and DataBinding in order to avoid boilerplate code

天大地大妈咪最大 提交于 2019-12-25 01:47:17

问题


I have a ParentFragment and a ChildFragment. They are working pretty fine.

My problem is that in the future I might create many child fragments and this makes me write this boilerplate code for every single child fragment. Thus, I would like to optimize my ParentFragment so that I do not have to write boilerplate code for every single new child framment I create in the future.

ParentFragment

abstract class ParentFragment<T: ViewDataBinding>: Fragment() {

    @LayoutRes
    abstract fun getLayoutResId(): Int

    protected lateinit var binding: T

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        super.onCreateView(inflater, container, savedInstanceState)

        return DataBindingUtil.inflate<T>(inflater, getLayoutResId(), container, false).apply { binding = this }.root
    }

ChildFragment

class ChildFragment: ParentFragment<FragmentChildBinding>() {

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        //THIS IS THE BOILERPLATE METHOD I AM TALKING ABOUT. 
        //I WOULD LIKE TO MOVE THIS CODE IN THE PARENTFRAGMENT
        initBinding() 
    }

    @LayoutRes
    override fun getLayoutResId() = R.layout.fragment_child

    fun initBinding() {
        val viewModel: ChildViewModel = getViewModel() //This method is from Koin
        binding.viewModel = viewModel
        binding.lifecycleOwner = this
    }

I tried to move this initBinding method code into ParentFragment but I got errors. Any suggestions would be greatly appreciated.


回答1:


So, your current issue is that you want to make your initBinding() function common in such a way that all child fragment can access it.

Now issue is that logic inside initBinding comes with koin dependency that gets resolved dynamically. So, each child fragment may have different ViewModel instance.


There is one way you can resolve this problem:

Take your ViewModel object as method parameter so that you can inject it from your child fragment while having method in parent fragment. check out below how:

initBinding() Method in ParentFragment with viewModel as method parameter that we will pass on from child fragments.

abstract class ParentFragment<T: ViewDataBinding>: Fragment() {

    // Other stuffs removed for sack of simplicity

    protected fun initBinding(viewModel: ViewModel) {
        binding.viewModel = viewModel
        binding.lifecycleOwner = this
    }
}

Accessing it from ChildFragment:

class ChildFragment: ParentFragment<FragmentChildBinding>() {

    // Other stuffs removed for sack of simplicity

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        // THIS IS HOW YOU CAN CONSUME THIS METHOD
        initBinding(getViewModel()) 
    }
}



回答2:


You need to call serVariable() on your binding object to set ViewModel in the parent Fragment. Optionally in your parent Fragment you can get ViewModel through abstract function if child Fragments have their own ViewModels.

You can follow this post to solve your problem.



来源:https://stackoverflow.com/questions/59279430/optimizing-parent-fragment-for-viewmodel-and-databinding-in-order-to-avoid-boile

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!