Search code examples
androidexoplayerandroid-viewbinding

Viewbinding within Android and Exoplayer


I'm using Android Exoplayer in one of my Fragment. Within Exoplayer I use a custom control layout"@layout/custom_player" for the controls. I have different elements within the layout for example I have a button element"optionBtn" which I want to connect to onclicklistener from my Kotlin code. Unfortunately that doesn't go very smoothly with view binding.

This is the XML Exoplayer

  <com.google.android.exoplayer2.ui.PlayerView
        android:id="@+id/playerVIew"
        app:resize_mode="fill"
        android:animateLayoutChanges="true"
        app:controller_layout_id="@layout/custom_player"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

This is the kotlin code

...
        private var binding: FragmentVideoBinding? = null
        private var btnsheetOptions: SheetOptionsBinding? = null
        private var sheetDialog: BottomSheetDialog? = null
        private var customPlayer: CustomPlayerBinding? = null
        
        override fun onCreateView(
            inflater: LayoutInflater, container: ViewGroup?,
            savedInstanceState: Bundle?
        ): View {

            btnsheetOptions = SheetOptionsBinding.inflate(inflater, null, false)
            sheetDialog = BottomSheetDialog(requireContext(), R.style.BottomSheetDialogTheme)
    
            binding = FragmentVideoBinding.inflate(inflater, container, false)
            customPlayer = CustomPlayerBinding.inflate(inflater, binding!!.root, true)
            
            return binding!!.root
    
        }
    
        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
   
            val simpleExoPlayer = SimpleExoPlayer.Builder(requireContext()).build()
            binding!!.playerVIew.player = simpleExoPlayer
            val mediaItem = MediaItem.fromUri(video.toString())
            simpleExoPlayer.addMediaItem(mediaItem)
            simpleExoPlayer.prepare()
            simpleExoPlayer.playWhenReady = true
    
    
            customPlayer!!.optionBtn.setOnClickListener {
    
               ...
    
            }
    
        }
    
    
    
        override fun onDestroy() {
            super.onDestroy()
            binding = null
            btnsheetOptions = null
            sheetDialog= null
            customPlayer = null
        }
    
    }
...

This way the layout is double-inflated on top of each other and one layout works with onclick listener and the other does not, which is not very useful.

Does anyone know the correct solution for this, I've been working on this for almost all afternoon.


Solution

  • You cannot use view binding with ExoPlayer's custom HUD layout. View Binding only works with layouts specifically inflated for the activity/fragment layouts. The custom HUD layout does NOT belong to the parent layout which the player is set in. It is inflated in a stand-alone fashion and not included in the layout (Hence the double-inflation). Since the custom layout is inflated and is not part of the original layout, you can't use view binding with all the ids contained in it.

    So what can you do if View Binding does not work with the custom layout's buttons ?
    You should use findViewById which is a function that belongs to Activity class. It's very easy to use and I assume you already know how as well:

        findViewById<ImageButton>(R.id.optionBtn).setOnClickListener {...}
        //The next line is for usage inside a fragment class
        activity?.findViewById<ImageButton>(R.id.optionBtn).setOnClickListener {...}
    

    Make sure you give the button an ID in your layout, for example:

        android:id="@id/optionBtn"
    

    What if you COULDN'T find the (R.id.optionBtn) ? This is a common problem, there are two R directories to be aware of. There is android.R which is usually used as R only. And there is the app's R directory. In order to distinguish between the two and avoid Unresolved reference issue, you should import your app's resources under a different name, this is done in the import section before your class code begins, add this:

    import com.example.app.R as appR
    

    Then you can try using appR.id.optionBtn instead. There is a very low chance you'd face this particular R.idissue but follow the solution above in case it happens.

    Bottom Line:
    1- Viewbinding only works for the activity/fragment layout connected to their context classes, it binds the parent layout's id and all their child views with actual binding variables. 2- If you wanna reach a layout that is not part of the activity/fragment layout directly, you should use findViewById instead. 3- If you have problems using the 'R.id', you should import your app's resources under a different name. I usually use 'X' instead of 'R'. But it's all a personal preference..