У меня есть Fragment
Я использую ExoPlayer
с собственным PlayerView
, размещенным на Activity
, у которого есть всплывающее диалоговое окно с другим PlayerView
, которым я намерен поделиться ExoPlayerInstance
с.Оба PlayerView
объявлены в XML макета.
Сам проигрыватель объявлен в Fragment
.
Когда Activity
PlayerView
занимает Fragment
s, объект Player передается просто отлично.Тем не менее, когда Activity
возвращает объект Player в Fragment
, по какой-то причине PlayerView
в Fragment
имеет значение null.
Я знаю, что я мог бы просто проверить NULL на PlayerView
, но это может не решить основную причину - причину, по которой findViewById для Fragment
внезапно возвращает ноль.
Итак, как это происходит, и как я работаю, чтобы решить или обойти,это?
РЕДАКТИРОВАТЬ:
Код, который я использую для заимствования / возврата объекта Player во фрагменте:
fun borrowPlayer(): SimpleExoPlayer {
vw_exo_player.player = null
vw_exo_player.fadeInvisible(100)
return player
}
fun returnPlayer() {
if(vw_exo_player != null) {
vw_exo_player.player = player
vw_exo_player.fadeVisible(100)
}
}
XML-фрагмент в основном выглядит следующим образом:
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/root_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
...
<com.google.android.exoplayer2.ui.PlayerView
android:id="@+id/vw_exo_player"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:resize_mode="zoom"
app:surface_type="texture_view"
app:use_controller="false"
tools:visibility="invisible" />
...
</android.support.constraint.ConstraintLayout>
Как видно здесь, XML-код макета фрагмента имеет этот идентификатор с идентификатором vw_exo_player
.
Обе функции, указанные выше, вызываются в Activity:
fun showPopupVideo(anchor: PopupVideoAnchor) {
if (popupVideoHolders[anchor]?.isOn == true) return
if (anchor == PopupVideoAnchor.WEB && (popupVideoHolders[PopupVideoAnchor.QNA]?.isOn == true || popupVideoHolders[PopupVideoAnchor.POLL]?.isOn == true)) {
return
}
Trace.i("Show Popup : $anchor")
if (pv_popup.player == null) {
pv_popup.player = findFragment(GameAVStreamFragment::class.java)?.borrowPlayer()
}
val x: Float = popupVideoHolders[anchor]?.x ?: 0F
val y: Float = popupVideoHolders[anchor]?.y ?: 0F
val w: Int = popupVideoHolders[anchor]?.w ?: 0
val h: Int = ((w.f / videoSize.w.f) * videoSize.h.f).i
val b: Float = if (popupVideoHolders[anchor]?.isBordered == true) 0.95F else 1F
val layoutParam = lay_popup_video.layoutParams
for (popupVideoHolder in popupVideoHolders) {
if (popupVideoHolder.value.isOn) {
loadAnimation(R.anim.fade_out).apply {
duration = 150
onEnd {
lay_popup_video.clipScale = 1F
lay_popup_video.x = x
lay_popup_video.y = y
lay_popup_video.layoutParams.width = w
lay_popup_video.layoutParams.height = h
lay_popup_video.requestLayout()
lay_popup_video_border.clipScale = b
popupVideoHolders[anchor]?.isOn = true
lay_popup_video.clearAnimation()
lay_popup_video.startAnimation(loadAnimation(R.anim.fade_in).apply { duration = 150 })
}
lay_popup_video.clearAnimation()
lay_popup_video.startAnimation(this)
}
return
}
}
popupVideoHolders[anchor]?.isOn = true
currPopupVideoAnim?.cancel()
currPopupVideoAnim = AnimatorSet().apply {
duration = 350L
onStart {
lay_popup_video.visible()
Trace.d("Start Popup Video Animation")
}
playTogether(
ObjectAnimator.ofFloat(lay_popup_video, "clipScale", lay_popup_video.clipScale, 1F),
ObjectAnimator.ofFloat(lay_popup_video, "x", lay_popup_video.x, x),
ObjectAnimator.ofFloat(lay_popup_video, "y", lay_popup_video.y, y),
ValueAnimator.ofInt(layoutParam.width, w).apply {
addUpdateListener {
val animW = it.animatedValue as Int
layoutParam.width = animW
lay_popup_video.requestLayout()
}
},
ValueAnimator.ofInt(layoutParam.height, h).apply {
addUpdateListener {
val animH = it.animatedValue as Int
layoutParam.height = animH
lay_popup_video.requestLayout()
}
},
ObjectAnimator.ofFloat(lay_popup_video_border, "clipScale", lay_popup_video_border.clipScale, b))
start()
}
}
fun closePopupVideo(anchor: PopupVideoAnchor) {
if (popupVideoHolders[anchor]?.isOn?.not() != false) return
popupVideoHolders[anchor]?.isOn = false
if (anchor == PopupVideoAnchor.WEB && (popupVideoHolders[PopupVideoAnchor.QNA]?.isOn == true || popupVideoHolders[PopupVideoAnchor.POLL]?.isOn == true)) {
return
}
val layoutParam = lay_popup_video.layoutParams
for (popupVideoHolder in popupVideoHolders) {
if (popupVideoHolder.value.isOn) {
loadAnimation(R.anim.fade_out).apply {
duration = 150
onEnd {
lay_popup_video.clipScale = 1F
lay_popup_video.x = popupVideoHolder.value.x
lay_popup_video.y = popupVideoHolder.value.y
lay_popup_video.layoutParams.width = popupVideoHolder.value.w
lay_popup_video.layoutParams.height = ((popupVideoHolder.value.w.f / videoSize.w.f) * videoSize.h.f).i
lay_popup_video.requestLayout()
lay_popup_video_border.clipScale = if (popupVideoHolder.value.isBordered) .95F else 1F
lay_popup_video.clearAnimation()
lay_popup_video.startAnimation(loadAnimation(R.anim.fade_in).apply { duration = 150 })
}
lay_popup_video.clearAnimation()
lay_popup_video.startAnimation(this)
}
return
}
}
currPopupVideoAnim?.cancel()
currPopupVideoAnim = AnimatorSet().apply {
duration = 350L
onEnd {
findFragment(GameAVStreamFragment::class.java)?.returnPlayer()
pv_popup.player = null
lay_popup_video.invisible()
}
playTogether(
ObjectAnimator.ofFloat(lay_popup_video, "clipScale", lay_popup_video.clipScale, 3.5F),
ObjectAnimator.ofFloat(lay_popup_video, "x", lay_popup_video.x, 0F),
ObjectAnimator.ofFloat(lay_popup_video, "y", lay_popup_video.y, 0F),
ValueAnimator.ofInt(layoutParam.width, videoSize.w).apply {
addUpdateListener {
val animW = it.animatedValue as Int
layoutParam.width = animW
lay_popup_video.requestLayout()
}
},
ValueAnimator.ofInt(layoutParam.height, videoSize.h).apply {
addUpdateListener {
val animH = it.animatedValue as Int
layoutParam.height = animH
lay_popup_video.requestLayout()
}
},
ObjectAnimator.ofFloat(lay_popup_video_border, "clipScale", lay_popup_video_border.clipScale, 3.5F))
start()
}
}
И showPopupVideo()
выше в основном вызывается в другом фрагменте, в то время как closePopupVideo()
вызывается после завершения 10-секундного таймера:
...
val streamFragment = findFragment(GameAVStreamFragment::class.java)
if (streamFragment?.isAudioOnly?.not() == true) {
if (activity.popupVideoHolders[GamePlayActivity.PopupVideoAnchor.WEB]?.isOn == true) {
activity.arrangeView(R.id.lay_popup_video, R.id.lay_qna)
} else {
activity.arrangeView(R.id.lay_head, R.id.lay_popup_video, R.id.lay_qna)
}
activity.showPopupVideo(GamePlayActivity.PopupVideoAnchor.QNA)
} else {
vw_hole_cover.visible()
}
...
... это может быть проблема с многопоточностью?