Android 中的 Viewbinding 和 Exoplayer。

4

我在一个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"/>

这是 Kotlin 代码

...
        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监听器,而另一个则不行,这并不是非常有用。

有没有人知道正确的解决方案?我已经花了下午几乎所有的时间在这个问题上。


我已经创建了一个答案,请看一下 -> https://stackoverflow.com/a/77495657/12553303 - undefined
2个回答

6
您不能使用View Binding与ExoPlayer的自定义HUD布局。View Binding仅适用于专门为activity/fragment布局创建的布局。自定义HUD布局不属于播放器设置在其中的父布局。它是以独立的方式膨胀的,并且未包含在布局中(因此会出现双倍膨胀)。由于自定义布局是被膨胀并且不是原始布局的一部分,因此您不能使用其中包含的所有id进行视图绑定。
那么,如果View Binding无法使用自定义布局的按钮,则可以使用属于Activity类的函数findViewById。这非常容易使用,我假设您已经知道如何使用了。
    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 目录。 一个是通常只用作 R 的 android.R 目录,另一个是应用程序的 R 目录。为了区分这两个目录并避免 "Unresolved reference" 问题,应在类代码开始之前的 import 部分添加以下内容来导入您应用的资源,并使用不同的名称引用: ```java import com.example.myapp.R; ```
import com.example.app.R as appR

那么你可以尝试使用 appR.id.optionBtn 代替。虽然很小的概率会出现这种特定的R.id问题,但如果发生了,请按照上述解决方案操作。

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


1
谢谢您的回答,不仅提供了文字和解释,还给出了解决方案。现在非常清晰了。再次感谢您。 - Riccoh
每当我在片段中尝试使用findViewbyid时,都会出现空指针异常。有没有解决办法? - Yesha Shah

2

在应用属性app:controller_layout_id的同时,不应该夸大数据绑定。

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

无论哪种方式,你只能拥有其中一种。


有点毫无意义的问题,除非提供custom_player.xml...因为它可能缺少一些必需的资源ID,而这些ID应该是存在的("自定义"可能有一定的限制,这可能包括:即使将这些ID隐藏在用户界面中,也必须提供某些资源ID)。XML标记在Android上非常重要,因为所有代码都针对它运行。ExoPlayer支持覆盖布局文件,除非给它们一个不同的名称。

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

我认为,当按文件名覆盖时,也应该可以进行数据绑定。
因为,当仅包含数据绑定时,父级仍然无法绑定它。
父级布局XML需要首先生成数据绑定。


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

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

在这种情况下,app:controller_layout_id不应该被设置。

我该如何在我的 Kotlin 代码中绑定这些元素?通常情况下,当我使用 "binding!!.playerVIew.optionBtn.setOnClickListener..."(saveBtn)时,使用 synthetic 一切正常。但是一旦我删除 synthetic,就没有办法再通过 bindings 绑定该元素了。我尝试了几种在 Bindings 中的方法,但迄今为止都没有成功。我知道如何在 "include" 中进行绑定,但在 Exoplayer 中似乎不起作用。 - Riccoh
1
找不到 setControllerLayoutId 方法。 - Jithish P N

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接