Android 和 Exoplayer 中的视图绑定

Posted

技术标签:

【中文标题】Android 和 Exoplayer 中的视图绑定【英文标题】:Viewbinding within Android and Exoplayer 【发布时间】:2021-12-10 09:28:42 【问题描述】:

我在我的一个 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_
        android:layout_
        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 监听器一起使用,而另一种则没有,这不是很有用。

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

【问题讨论】:

【参考方案1】:

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

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

    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 问题,您应该以不同的名称导入应用程序的资源,这是在您的类代码开始之前的import 部分完成的,添加以下内容:

import com.example.app.R as appR

然后您可以尝试改用appR.id.optionBtn。您遇到这个特定的R.id问题的可能性非常低,但如果发生这种情况,请遵循上面的解决方案。

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

【讨论】:

感谢您的回答,您不仅提供了文字和解释,还提供了解决方案。现在很清楚了。再次,非常感谢。【参考方案2】:

不应夸大数据绑定,同时还要应用属性app:controller_layout_id

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

这两种方式都只能有。


不知何故,这个问题毫无意义,除非提供 custom_player.xml ...因为它可能缺少一些强制性资源 ID,这些资源 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 不得设置。

【讨论】:

我可以通过什么方式在我的 kotlin 代码中绑定这些元素?通常,当我使用“binding!!.playerVIew.optionBtn.setOnClickListener ...”(saveBtn)时,一切都可以正常使用合成。一旦我删除了合成,就无法通过绑定再次绑定该元素。我在 Bindings 中尝试了几种方法,但到目前为止没有运气。我知道我在“包含”中绑定的方式,但使用 Exoplayer 似乎不起作用。

以上是关于Android 和 Exoplayer 中的视图绑定的主要内容,如果未能解决你的问题,请参考以下文章

使用 Kotlin 的 Android TV 中的 ExoPlayer

Android TV 中的 ExoPlayer 以纵向模式而不是横向模式播放视频

Android 无法生成视图绑定器 com.sun.tools.javac.code.Symbol$CompletionFailure:

android tv 中的 Exoplayer 不会在直播中重现 (.m3u8) 文件

Android 依赖 'com.google.android.exoplayer:exoplayer' 有不同版本的编译(r2.1.0)和运行时(2.9.1)类路径

如何在 android 中更改 ExoPlayer 字幕位置?