Android 和 Exoplayer 中的视图绑定

Viewbinding within Android and Exoplayer

我在我的一个 Fragment 中使用 Android Exoplayer。 在 Exoplayer 中,我为控件使用自定义控件布局“@layout/custom_player”。 我在布局中有不同的元素,例如我有一个按钮元素“optionBtn”,我想从我的 Kotlin 代码连接到 onclicklistener。不幸的是,视图绑定并不是很顺利。

这是 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"/>

这是科特林代码

...
        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
        }
    
    }
...

这种布局在彼此之上双重膨胀,一个布局适用于 onclick 侦听器而另一个不适用,这不是很有用。

有谁知道正确的解决方案吗,我几乎整个下午都在研究这个问题。

不应该膨胀数据绑定,同时还应用属性 app:controller_layout_id:

customPlayer = CustomPlayerBinding.inflate(inflater, binding!!.root, true)

一个人只能这样。


这个问题毫无意义,除非提供 custom_player.xml ...因为它可能缺少一些强制性的资源 ID,这些资源 ID 应该存在(“自定义”可能允许的内容有某些限制,其中可能包括:必须提供某些资源 ID,即使对用户隐藏这些)。 XML 标记在 Android 上非常重要 - 因为所有代码都针对它运行。 ExoPlayer 支持 overriding 布局文件,除非给它们一个不同的名称。

请参考原始布局资源,特别是它们的文件名和resId:
https://github.com/google/ExoPlayer/tree/release-v2/library/ui/src/main/res/layout

我假设,当通过文件名覆盖时,也应该可以进行数据绑定。
因为,只有 include 有数据绑定时,父级仍然不能绑定它。
首先,父布局 XML 需要生成数据绑定。


使用 .setControllerLayoutId(),实际上可以在分配 View 之前对其进行数据绑定:

customPlayer = CustomPlayerBinding.inflate(inflater, binding!!.root, true)
binding.playerView.setControllerLayoutId(customPlayer!!.root)

这种情况下app:controller_layout_id不能设置。

不能将视图绑定与 ExoPlayer 的自定义 HUD 布局一起使用。视图绑定仅适用于专门为 activity/fragment 布局扩充的布局。自定义 HUD 布局不属于玩家所在的父级布局。它以独立的方式膨胀,不包含在布局中(因此是双 inflation)。由于自定义布局已膨胀并且不是原始布局的一部分,因此您不能将视图绑定与其中包含的所有 ID 一起使用。

那么,如果视图绑定不适用于自定义布局的按钮,您该怎么办?
您应该使用 findViewById,这是属于 Activity class 的函数。 它非常易于使用,我想您也已经知道如何使用了:

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

确保在布局中为按钮提供 ID,例如:

    android:id="@id/optionBtn"

如果您无法 找到 (R.id.optionBtn) 怎么办? 这是一个常见问题,有两个 R 目录需要注意。 有 android.R 通常只用作 R。还有应用程序的 R 目录。为了区分两者并避免 Unresolved reference 问题,您应该以不同的名称导入应用程序的资源,这是在 class 代码开始之前的 import 部分中完成的,添加此:

import com.example.app.R as appR

那么您可以尝试使用 appR.id.optionBtn 代替。您遇到这个特定 R.id 问题的可能性非常小,但请按照上面的解决方案以防万一。

底线
1- Viewbinding 仅适用于连接到其上下文 classes 的 activity/fragment 布局,它将父布局的 id 及其所有子视图与实际绑定变量绑定。 2- 如果您想直接访问不属于 activity/fragment 布局的布局,则应改用 findViewById。 3- 如果您在使用 'R.id' 时遇到问题,您应该以不同的名称导入应用程序的资源。我通常使用 'X' 而不是 'R'。但这完全是个人喜好..