androidbroadcast / ViewBindingPropertyDelegate

Make work with Android View Binding simpler
https://proandroiddev.com/make-android-view-binding-great-with-kotlin-b71dd9c87719
Apache License 2.0
1.42k stars 102 forks source link

How to correctly use a generic? View blank and onViewCreated() not called in Fragment nor Base #123

Open baggednismo opened 6 months ago

baggednismo commented 6 months ago

I have an app with lots of fragments. It does not use view models. I have been using BaseFragment() : Fragment() as I need onCreateView() and onViewCreated() to do all of the same stuff in every view (set entry animations and add an animation delay for the transitions).

Following issue tracked previously here

I attempt to setup a new BaseVBFragment as such

abstract class BaseVBFragment<VB : ViewBinding>(viewBindingClass: Class<VB>) : Fragment() {

    protected val binding: VB by viewBinding(viewBindingClass)

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        Timber.d("-> onCreateView()")
        setHasOptionsMenu(true)
        setEntryAnimations()
        return super.onCreateView(inflater, container, savedInstanceState)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        Timber.d("-> onViewCreated()")
        super.onViewCreated(view, savedInstanceState)
        delayAnimation(view)
    }

    override fun onResume() {
        logFragmentAnalytics()
        super.onResume()
    }
}

I setup my Fragment as such

class MyFragment : BaseVBFragment<MyFragmentBinding>(MyFragmentBinding::class.java) {

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        Timber.d("-> onViewCreated()")
        super.onViewCreated(view, savedInstanceState)
    }

    override fun onResume() {
        Timber.d("-> onResume()")
        super.onResume()

        // Can't access the Fragment View's LifecycleOwner for MyFragment{f4db0e9} when getView() is null i.e., before onCreateView() or after onDestroyView()
        observable.observe(viewLifecycleOwner) { /* do something on event */ }
    }

}

So with the error of not being able to access viewLifecycleOwner in onResume(), I moved that to MyFragment.onViewCreated()

This resolved the hard error but the view is completely blank. Looking at logs, MyFragment nor BaseVBFragment runs onViewCreated().

ActivityExtensionsKt                      D  -> hideSoftKeyboard()
BaseVBFragment                            D  -> onCreateView()
UpdateEmai...ssFragment                   D  -> onResume()
FragmentExtensionsKt                      D  -> logFragmentAnalytics()
FrameEvents                               E  updateAcquireFence: Did not find frame.
FrameEvents                               E  updateAcquireFence: Did not find frame.
FrameEvents                               E  updateAcquireFence: Did not find frame.
...
kirich1409 commented 3 months ago

Hi. I didn't find where you access ViewBinding instance in your code. The most common mistake is accessing it in callback of async calls. Before that you need to check that you view is still exists:

class AnyFragment : Fragment {

    fun anyFuncation() {
         // Start operation or subscribe on Flow/LiveData/Observable
         // that call callback async
         source.doOnResult {
             if(this@AnyFramgnet.view != null) {
                 //do operations using ViewBinding instance
             }
         }
    }
}