I have a DialogFragment
with a ViewPager2
:
public class LightboxFragment extends DialogFragment {
private ViewPager2 viewPager;
private MyViewPagerAdapter myViewPagerAdapter;
public static LightboxFragment newInstance() {
LightboxFragment fragment = new LightboxFragment();
return fragment;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_lightbox, container, false);
viewPager = v.findViewById(R.id.viewPager);
FrameLayout closeButtonContainer = v.findViewById(R.id.close_button_container);
closeButtonContainer.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
}
});
myViewPagerAdapter = new MyViewPagerAdapter(getActivity());
viewPager.setAdapter(myViewPagerAdapter);
return v;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public class MyViewPagerAdapter extends FragmentStateAdapter {
public MyViewPagerAdapter(FragmentActivity fa) {
super(fa);
}
@NonNull
@Override
public Fragment createFragment(int position) {
LightboxVideoFragment fragment = new LightboxVideoFragment();
return fragment;
}
@Override
public int getItemCount() {
return items.size();
}
}
}
And my LightboxVideoFragment
looks something like this:
public class LightboxVideoFragment extends Fragment {
private SimpleExoPlayer exoPlayer;
private PlayerView playerView;
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.slideshow_video, container, false);
}
@Override
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
playerView = view.findViewById(R.id.player_view);
MediaItem mediaItem = MediaItem.fromUri(media.getUrls().getMp4());
exoPlayer = new SimpleExoPlayer.Builder(getContext()).build();
exoPlayer.setRepeatMode(Player.REPEAT_MODE_ALL);
playerView.setPlayer(exoPlayer);
exoPlayer.setMediaItem(mediaItem);
exoPlayer.prepare();
exoPlayer.play();
}
@Override
public void onResume() {
super.onResume();
if (exoPlayer != null) {
exoPlayer.play();
}
}
@Override
public void onPause() {
super.onPause();
if (exoPlayer != null) {
exoPlayer.pause();
}
}
@Override
public void onDetach() {
super.onDetach();
if (exoPlayer != null) {
exoPlayer.release();
}
}
}
My problem is this: When the DialogFragment
is dismissed, the audio from the fragment's video is still playing. Why is this? I've tried adding onDestroy
in my fragment and setting breakpoints there, but the breakpoint is never called when the dialog is dismissed, nor is onPause
or onDetach
.
Does this also mean that the ExoPlayer
instance is also still alive when the dialog is dismissed?
How can I stop the video's audio when the dialog is dismissed?
I don't use viewpager2 inside another Fragment but based on the documentation and the source code of viewpager2 I think you are creating the adapter incorrectly when doing it from a Fragment.
In the class LightboxFragment
try changing line
myViewPagerAdapter = new MyViewPagerAdapter(getActivity());
to
myViewPagerAdapter = new MyViewPagerAdapter(this);
This is because based on the documentation https://developer.android.com/reference/androidx/viewpager2/adapter/FragmentStateAdapter#FragmentStateAdapter(androidx.fragment.app.Fragment)
Fragment: if the ViewPager2 lives directly in a Fragment subclass.
You are using it as if the Viewpager2 is living directly in the host activity.
This means you are putting LightboxVideoFragment
in the same FragmentManager as LightboxFragment
and the Lifecycle changes to LightboxFragment
don't affect what are basically siblings to it (not children as they should be)
If you look at the source code of viewpager2 for the constructors as well
The correct constructor ties the Fragments in the viewpager2 adaptor to a host Fragment via getChildFragmentManager()
and the Fragment's lifecycle and not to the Activity's
lifecycle.
(I've not experimented or tested this just knowledge from the docs and reading the source code).