Exoplayer 停止在 Fragment 中的 RecyclerView 中不工作
Exoplayer stop not working in RecyclerView in Fragment
我正在为我的 RecyclerView 使用 FirestorePagingAdapter。
当片段关闭时,我尝试在 onStop、onPasue、onDestroy 方法中停止 exoplayer,但是
它不能正常工作,它只停止 Recycler 视图中的最后一个视频,但我不明白
这里的主要问题是什么。
@Override
public void onStop() {
super.onStop();
adapter.stopListening();
if (HomeVideoHolder.simpleExoPlayer != null) {
HomeVideoHolder.simpleExoPlayer.stop();
}
}
@Override
public void onDestroy() {
super.onDestroy();
adapter.stopListening();
if (HomeVideoHolder.simpleExoPlayer != null) {
HomeVideoHolder.simpleExoPlayer.stop();
}
}
@Override
public void onPause() {
super.onPause();
adapter.stopListening();
if (HomeVideoHolder.simpleExoPlayer != null) {
HomeVideoHolder.simpleExoPlayer.stop();
}
我在 HomeVideoHolder 中将 simpleExoplayer 声明为 public 静态。
public static PlayerView videoViewpath;
public static SimpleExoPlayer simpleExoPlayer;
我也尝试停止、释放、setPlayWhenReady(false) 和寻求视频结束
停止 exoplayer。
但是每种方法对我来说都是一样的结果。他们只停止 recyclerView 的最后一个视频。
请给我一个解决这个问题的办法......
我的适配器代码...
adapter=new FirestorePagingAdapter<HomeClass, HomeVideoHolder>(options) {
@Override
protected void onBindViewHolder(@NonNull HomeVideoHolder holder, int position, @NonNull HomeClass model) {
holder.setVideoView(getActivity(),model.getAd(),model.getpId(),model.getcUid(),model.getUid(),model.getPic(),model.getVideo(),model.getcT());
}
@NonNull
@Override
public HomeVideoHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new HomeVideoHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.home_video_item,parent,false));
}
@Override
protected void onLoadingStateChanged(@NonNull LoadingState state) {
switch (state) {
case LOADING_INITIAL:
// The initial load has
swipeRefreshLayout.setRefreshing(true);
break;
// ...
case LOADING_MORE:
// The adapter has started to load an additional page
vLoadMore.setVisibility(View.VISIBLE);
break;
// ...
case LOADED:
// The previous load (either initial or additional) completed
swipeRefreshLayout.setRefreshing(false);
vLoadMore.setVisibility(View.INVISIBLE);
break;
// ...
case FINISHED:
vLoadMore.setVisibility(View.INVISIBLE);
break;
case ERROR:
// The previous load (either initial or additional) failed. Call
adapter.retry();
swipeRefreshLayout.setRefreshing(true);
// the retry() method in order to retry the load operation.
break;
// ...
}
}
};
我的 viewHolder 代码....
public void setVideoView(Activity activity,String ad, String pId, String cUid, String uid, String pic, String video, String cT) {
final CircleImageView chanelProfile=view.findViewById(R.id.cPicH);
final TextView chanelName=view.findViewById(R.id.cNameH);
final TextView videoCaption=view.findViewById(R.id.vDesH);
final ImageView videoThreeDot=view.findViewById(R.id.threeDotHome);
Pkey=pId;
user=FirebaseAuth.getInstance().getCurrentUser().getUid();
videoCaption.setText(cT);
setPlayer(video);
}
private void setPlayer(String video) {
if (playCode.equals("true")) {
LoadControl loadControl = new DefaultLoadControl();
BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
TrackSelector trackSelector = new DefaultTrackSelector(
new AdaptiveTrackSelection.Factory(bandwidthMeter)
);
simpleExoPlayer = ExoPlayerFactory.newSimpleInstance(
view.getContext(), trackSelector, loadControl
);
DefaultHttpDataSourceFactory factory = new DefaultHttpDataSourceFactory(
"Video"
);
ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
MediaSource mediaSource = new ExtractorMediaSource(Uri.parse(Video),
factory, extractorsFactory, null, null
);
videoViewpath.setPlayer(simpleExoPlayer);
videoViewpath.setKeepScreenOn(true);
simpleExoPlayer.prepare(mediaSource);
simpleExoPlayer.setPlayWhenReady(false);
simpleExoPlayer.addListener(new Player.DefaultEventListener() {
@Override
public void onTimelineChanged(Timeline timeline, Object manifest, int reason) {
super.onTimelineChanged(timeline, manifest, reason);
}
@Override
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
super.onTracksChanged(trackGroups, trackSelections);
}
@Override
public void onLoadingChanged(boolean isLoading) {
super.onLoadingChanged(isLoading);
}
@Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
super.onPlayerStateChanged(playWhenReady, playbackState);
switch (playbackState) {
case Player.STATE_BUFFERING:
progressBar.setVisibility(View.VISIBLE);
break;
case Player.STATE_ENDED:
break;
case Player.STATE_IDLE:
break;
case Player.STATE_READY:
addViwes();
progressBar.setVisibility(View.INVISIBLE);
break;
default:
break;
}
}
@Override
public void onRepeatModeChanged(int repeatMode) {
super.onRepeatModeChanged(repeatMode);
}
@Override
public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {
super.onShuffleModeEnabledChanged(shuffleModeEnabled);
}
@Override
public void onPlayerError(ExoPlaybackException error) {
super.onPlayerError(error);
// simpleExoPlayer.prepare(mediaSource);
// simpleExoPlayer.setPlayWhenReady(false);
}
@Override
public void onPositionDiscontinuity(int reason) {
super.onPositionDiscontinuity(reason);
}
@Override
public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
super.onPlaybackParametersChanged(playbackParameters);
}
@Override
public void onSeekProcessed() {
super.onSeekProcessed();
}
});
}else {
simpleExoPlayer.stop();
simpleExoPlayer.release();
simpleExoPlayer.clearVideoSurface();
videoViewpath.setPlayer(null);
}
}
不要将 PlayerView
和 SimpleExoPlayer
声明为 static
,这是错误的方法...您仅保留对最后一个视频播放器实例的引用并且你想让他们都 pause/stop 全部。每个 HomeViewHolder
应该只保留自己的玩家参考,static
字段在所有参考保持实例中只保留一个实例 class ("owner", HomeViewHolder
)
从 onPause
、onStop
和 onDestroy
、播放器实例(非 static
) 无论如何都无法访问
覆盖适配器中的onViewDetachedFromWindow(HomeVideoHolder holder)
and/oronViewRecycled(HomeVideoHolder holder)
方法,在这个地方pause/stop这个单独的播放器实例附加到单个HomeVideoHolder
让适配器在单个项目获得 recycled/detached 时停止所有玩家,而不仅仅是在销毁 Activity
/Fragment
时。目前你可能有一些内存泄漏,因为新手玩家可能会留在内存中播放一些视频而你没有参考它(只有最后一个,static
字段如上所述)来释放资源......当你销毁 RecyclerView
然后连接到它的适配器将 recycle/destroy 所有当前存在的 HomeViewPager
s,确保你可以 recyclerView.setAdapter(null)
在 onDestroy
中(在 super
称呼)。还要检查此模式(回收视图)如何与 RecyclerView.Adapter 的所有可覆盖方法中的某些 Log
调用一起工作,这些方法以 on...
开头(例如,如 3 中所述)
您应该保留一个 ExoPlayer 实例。在 Activity 中创建它,然后通过构造函数传递给适配器。这是我的代码:
适配器:
class VideoAdapter( private val mContext: Context, val exoPlayer: ExoPlayer, options: FirestoreRecyclerOptions<VideoModel?>) :[...]
exoPlayer
.also { exoPlayer ->
styledPlayerView.player = exoPlayer
exoPlayer.seekTo(currentWindow, playbackPosition)
styledPlayerView.setShowBuffering(StyledPlayerView.SHOW_BUFFERING_WHEN_PLAYING)
styledPlayerView.useController = false
exoPlayer.repeatMode = Player.REPEAT_MODE_ONE
}
Activity:
private lateinit var exoPlayer: ExoPlayer [...]
exoPlayer = ExoPlayer.Builder(requireContext())
.build() [...]
videoAdapter = VideoAdapter(requireContext(), exoPlayer, options)
然后在我的活动 onStop() 方法中:
override fun onStop() {
super.onStop()
videoAdapter.stopListening()
exoPlayer.release()
}
我正在为我的 RecyclerView 使用 FirestorePagingAdapter。
当片段关闭时,我尝试在 onStop、onPasue、onDestroy 方法中停止 exoplayer,但是 它不能正常工作,它只停止 Recycler 视图中的最后一个视频,但我不明白 这里的主要问题是什么。
@Override
public void onStop() {
super.onStop();
adapter.stopListening();
if (HomeVideoHolder.simpleExoPlayer != null) {
HomeVideoHolder.simpleExoPlayer.stop();
}
}
@Override
public void onDestroy() {
super.onDestroy();
adapter.stopListening();
if (HomeVideoHolder.simpleExoPlayer != null) {
HomeVideoHolder.simpleExoPlayer.stop();
}
}
@Override
public void onPause() {
super.onPause();
adapter.stopListening();
if (HomeVideoHolder.simpleExoPlayer != null) {
HomeVideoHolder.simpleExoPlayer.stop();
}
我在 HomeVideoHolder 中将 simpleExoplayer 声明为 public 静态。
public static PlayerView videoViewpath;
public static SimpleExoPlayer simpleExoPlayer;
我也尝试停止、释放、setPlayWhenReady(false) 和寻求视频结束 停止 exoplayer。
但是每种方法对我来说都是一样的结果。他们只停止 recyclerView 的最后一个视频。
请给我一个解决这个问题的办法......
我的适配器代码...
adapter=new FirestorePagingAdapter<HomeClass, HomeVideoHolder>(options) {
@Override
protected void onBindViewHolder(@NonNull HomeVideoHolder holder, int position, @NonNull HomeClass model) {
holder.setVideoView(getActivity(),model.getAd(),model.getpId(),model.getcUid(),model.getUid(),model.getPic(),model.getVideo(),model.getcT());
}
@NonNull
@Override
public HomeVideoHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new HomeVideoHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.home_video_item,parent,false));
}
@Override
protected void onLoadingStateChanged(@NonNull LoadingState state) {
switch (state) {
case LOADING_INITIAL:
// The initial load has
swipeRefreshLayout.setRefreshing(true);
break;
// ...
case LOADING_MORE:
// The adapter has started to load an additional page
vLoadMore.setVisibility(View.VISIBLE);
break;
// ...
case LOADED:
// The previous load (either initial or additional) completed
swipeRefreshLayout.setRefreshing(false);
vLoadMore.setVisibility(View.INVISIBLE);
break;
// ...
case FINISHED:
vLoadMore.setVisibility(View.INVISIBLE);
break;
case ERROR:
// The previous load (either initial or additional) failed. Call
adapter.retry();
swipeRefreshLayout.setRefreshing(true);
// the retry() method in order to retry the load operation.
break;
// ...
}
}
};
我的 viewHolder 代码....
public void setVideoView(Activity activity,String ad, String pId, String cUid, String uid, String pic, String video, String cT) {
final CircleImageView chanelProfile=view.findViewById(R.id.cPicH);
final TextView chanelName=view.findViewById(R.id.cNameH);
final TextView videoCaption=view.findViewById(R.id.vDesH);
final ImageView videoThreeDot=view.findViewById(R.id.threeDotHome);
Pkey=pId;
user=FirebaseAuth.getInstance().getCurrentUser().getUid();
videoCaption.setText(cT);
setPlayer(video);
}
private void setPlayer(String video) {
if (playCode.equals("true")) {
LoadControl loadControl = new DefaultLoadControl();
BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
TrackSelector trackSelector = new DefaultTrackSelector(
new AdaptiveTrackSelection.Factory(bandwidthMeter)
);
simpleExoPlayer = ExoPlayerFactory.newSimpleInstance(
view.getContext(), trackSelector, loadControl
);
DefaultHttpDataSourceFactory factory = new DefaultHttpDataSourceFactory(
"Video"
);
ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
MediaSource mediaSource = new ExtractorMediaSource(Uri.parse(Video),
factory, extractorsFactory, null, null
);
videoViewpath.setPlayer(simpleExoPlayer);
videoViewpath.setKeepScreenOn(true);
simpleExoPlayer.prepare(mediaSource);
simpleExoPlayer.setPlayWhenReady(false);
simpleExoPlayer.addListener(new Player.DefaultEventListener() {
@Override
public void onTimelineChanged(Timeline timeline, Object manifest, int reason) {
super.onTimelineChanged(timeline, manifest, reason);
}
@Override
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
super.onTracksChanged(trackGroups, trackSelections);
}
@Override
public void onLoadingChanged(boolean isLoading) {
super.onLoadingChanged(isLoading);
}
@Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
super.onPlayerStateChanged(playWhenReady, playbackState);
switch (playbackState) {
case Player.STATE_BUFFERING:
progressBar.setVisibility(View.VISIBLE);
break;
case Player.STATE_ENDED:
break;
case Player.STATE_IDLE:
break;
case Player.STATE_READY:
addViwes();
progressBar.setVisibility(View.INVISIBLE);
break;
default:
break;
}
}
@Override
public void onRepeatModeChanged(int repeatMode) {
super.onRepeatModeChanged(repeatMode);
}
@Override
public void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {
super.onShuffleModeEnabledChanged(shuffleModeEnabled);
}
@Override
public void onPlayerError(ExoPlaybackException error) {
super.onPlayerError(error);
// simpleExoPlayer.prepare(mediaSource);
// simpleExoPlayer.setPlayWhenReady(false);
}
@Override
public void onPositionDiscontinuity(int reason) {
super.onPositionDiscontinuity(reason);
}
@Override
public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
super.onPlaybackParametersChanged(playbackParameters);
}
@Override
public void onSeekProcessed() {
super.onSeekProcessed();
}
});
}else {
simpleExoPlayer.stop();
simpleExoPlayer.release();
simpleExoPlayer.clearVideoSurface();
videoViewpath.setPlayer(null);
}
}
不要将
PlayerView
和SimpleExoPlayer
声明为static
,这是错误的方法...您仅保留对最后一个视频播放器实例的引用并且你想让他们都 pause/stop 全部。每个HomeViewHolder
应该只保留自己的玩家参考,static
字段在所有参考保持实例中只保留一个实例 class ("owner",HomeViewHolder
)从
onPause
、onStop
和onDestroy
、播放器实例(非static
) 无论如何都无法访问覆盖适配器中的
onViewDetachedFromWindow(HomeVideoHolder holder)
and/oronViewRecycled(HomeVideoHolder holder)
方法,在这个地方pause/stop这个单独的播放器实例附加到单个HomeVideoHolder
让适配器在单个项目获得 recycled/detached 时停止所有玩家,而不仅仅是在销毁 Activity
/Fragment
时。目前你可能有一些内存泄漏,因为新手玩家可能会留在内存中播放一些视频而你没有参考它(只有最后一个,static
字段如上所述)来释放资源......当你销毁 RecyclerView
然后连接到它的适配器将 recycle/destroy 所有当前存在的 HomeViewPager
s,确保你可以 recyclerView.setAdapter(null)
在 onDestroy
中(在 super
称呼)。还要检查此模式(回收视图)如何与 RecyclerView.Adapter 的所有可覆盖方法中的某些 Log
调用一起工作,这些方法以 on...
开头(例如,如 3 中所述)
您应该保留一个 ExoPlayer 实例。在 Activity 中创建它,然后通过构造函数传递给适配器。这是我的代码:
适配器:
class VideoAdapter( private val mContext: Context, val exoPlayer: ExoPlayer, options: FirestoreRecyclerOptions<VideoModel?>) :[...]
exoPlayer
.also { exoPlayer ->
styledPlayerView.player = exoPlayer
exoPlayer.seekTo(currentWindow, playbackPosition)
styledPlayerView.setShowBuffering(StyledPlayerView.SHOW_BUFFERING_WHEN_PLAYING)
styledPlayerView.useController = false
exoPlayer.repeatMode = Player.REPEAT_MODE_ONE
}
Activity:
private lateinit var exoPlayer: ExoPlayer [...]
exoPlayer = ExoPlayer.Builder(requireContext())
.build() [...]
videoAdapter = VideoAdapter(requireContext(), exoPlayer, options)
然后在我的活动 onStop() 方法中:
override fun onStop() {
super.onStop()
videoAdapter.stopListening()
exoPlayer.release()
}