Fragment.viewLifecycleOwnerLiveData.observe doesn't call with kodein

777 Views Asked by At

i'm making an app and i want to separate my UI logic into multiple UI classes with BaseUi class being lifecycle aware. I'm using Kodein as my DI and i have an issue with fragment.viewLifecycleOwnerLiveData.observe not being called when instance of my ui class is being retrieved by Kodein. Here is my Fragment class:

class ListFragment : Fragment(), DIAware {

    override val di: DI by closestDI()
    override val diTrigger: DITrigger = DITrigger()

    private var binding: FragmentMoviesBinding? = null

    private val fragmentBinding get() = binding

    private val kodeinMoviesUi: MoviesUi by instance() //fragment does not observe viewLifecycleOwnerLiveData

    private val moviesUi: MoviesUi = MoviesUi(this) //fragment now observe viewLifecycleOwnerLiveData

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        binding = FragmentMoviesBinding.inflate(inflater, container, false)
        return binding?.root
    }

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

        diTrigger.trigger()
    }

    override fun onDestroyView() {
        super.onDestroyView()
        binding = null
    }
}

BaseUi class:

abstract class BaseUi<F : Fragment>(private val fragment: F) : LifecycleObserver {

    init {
        fragment.viewLifecycleOwnerLiveData.observe(fragment, { subscribeToLifecycle() })
    }

    private fun subscribeToLifecycle() {
        fragment.viewLifecycleOwner.lifecycle.addObserver(object : LifecycleObserver {
            @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
            fun onCreate() {
                onViewCreated()
            }
        })
    }

    abstract fun onViewCreated()
}

And UiModule:

val uiModule = DI.Module("uiModule") {
    bind<ListFragment>() with provider { ListFragment() }
    bind<MoviesUi>() with provider { MoviesUi(instance()) }
}
1

There are 1 best solutions below

0
On

Cross post from https://github.com/Kodein-Framework/Kodein-DI/issues/353

Here is your problem bind<ListFragment>() with provider { ListFragment() }.

You bound the ListFragment with a provider, meaning every time you ask to the container it will create an instance of ListFragment. So, when you inject MoviesUi with private val kodeinMoviesUi: MoviesUi by instance(), it gets another instance of ListFragment.

I suggest that you define the binding for MoviesUi as a factory, waiting to receive a ListFragment instance: bind<MoviesUi>() with factory {fragment: ListFragment -> MoviesUi(fragment) } then you can inject it in the ListFragment like: private val kodeinMoviesUi: MoviesUi by instance(args = this)