Как реализовать воспроизведение видео с помощью VideoView внутри вложенной ViewPager2?

#android #android-layout #android-viewpager #android-videoview #android-viewpager2

#Android #android-макет #android-viewpager #android-videoview #android-viewpager2

Вопрос:

  • Я намерен реализовать вложенный ViewPager с использованием ViewPager2. Каждая страница ViewPager с горизонтальной прокруткой содержит ViewPager с вертикальной прокруткой, который содержит список видео по категориям. Автоматическое воспроизведение видео, когда страница видна пользователю, и остановка, когда страница невидима.
  • Мое решение:

CategoryPagerAdapter для горизонтальной прокрутки ViewPager

 public class CategoryPagerAdapter extends FragmentStateAdapter {

    List<Category> categories = new ArrayList<>();

    public CategoryPagerAdapter(@NonNull Fragment fragment) {
        super(fragment);
    }

    @NonNull
    @Override
    public Fragment createFragment(int position) {
        Fragment fragment = new ListVideoFragment();
        Bundle args = new Bundle();
        // Send category id to ListVideoFragment
        // This fragment contains the vertical-scroll ViewPager
        args.putLong(ListVideopaperFragment.EXTRA_CATEGORY_ID, categories.get(position).getId());
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public int getItemCount() {
        return Math.max(categories.size(), 0);
    }

    public void addCategories(List<Category> categories) {
        this.categories.addAll(categories);
        notifyDataSetChanged();
    }
   }
  

ListVideoPagerAdapter для вертикальной прокрутки ViewPager

     public class ListVideoPagerAdapter extends FragmentStateAdapter {

    List<Video> videos = new ArrayList<>();

    public ListWallpaperPagerAdapter(@NonNull Fragment fragment) {
        super(fragment);
    }

    @NonNull
    @Override
    public Fragment createFragment(int position) {
        Fragment fragment;         
        fragment = new VideoPreviewFragment();
        Bundle args = new Bundle();
        args.putString(EXTRA_VIDEO_URI, videos.get(position).getVideoPath());
        args.putLong(EXTRA_VIDEO_ID, videos.get(position).getId());
        fragment.setArguments(args);
        
        return fragment;
    }

    @Override
    public int getItemCount() {
        return Math.max(videos.size(), 0);
    }

    public void addVideos(List<Video> videos) {
        this.videos.addAll(videos);
         notifyDataSetChanged();
    } 
   } 
  

Это фрагмент, VideoPreviewFragment который содержит a VideoView в качестве видеопроигрывателя и содержится внутри каждой страницы ViewPager с вертикальной прокруткой.

  private static VideoPreviewFragment fragment = null;
    private VideoView videoView;
    private String videoURI;
    private long videoId;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Bundle args = getArguments();
        if (args != null) {
            videoURI = args.getString(EXTRA_VIDEO_URI);
            videoId = args.getLong(EXTRA_VIDEO_ID);          
        }      
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.wallpaper_view, container, false);
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        videoView = requireActivity().findViewById(R.id.video_view);
        initializePlayer();
    }

    @Override
    public void onResume() {
        super.onResume();
        if (videoView != null) {
            videoView.start();
            Log.d(TAG, "Playing video:"   videoURI);
        }
    }

    @Override
    public void onStop() {
        if (videoView != null amp;amp; videoView.canPause()) {
            videoView.pause();
            Log.d(TAG, "Pause video: "   videoURI);
        }
        super.onStop();
    }

    @Override
    public void onDestroy() {
        videoView.stopPlayback();
        Log.d(TAG, "releasePlayer:"   videoURI); 
        super.onDestroy();
    }
 
    // When scrolling to another video, the current video will be not visible, stop playback
    @Override
    public void setMenuVisibility(boolean isVisible) {
        super.setMenuVisibility(isVisible);
        if (!isVisible) {
            videoView.stopPlayback();
            Log.d(TAG, "releasePlayer:"   videoURI);
        }
    }

    int currentPosition = 0;
    private void initializePlayer() {
        videoView.setVideoURI(getMedia(videoURI));
        videoView.seekTo(1);
        videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
            @SuppressLint("LongLogTag")
            @Override
            public void onPrepared(MediaPlayer mp) {
                Log.d(TAG, "onPrepared video: "   videoURI);
                mp.setLooping(true);
            }
        });
        
        videoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
            @SuppressLint("LongLogTag")
            @Override
            public void onCompletion(MediaPlayer mp) {
                Log.d(TAG, "onCompletion video: "   videoURI);
                videoView.seekTo(0);
            }
        });
     
        videoView.setOnClickListener(new View.OnClickListener() {
            @SuppressLint("LongLogTag")
            @Override
            public void onClick(View v) {
                Log.d(TAG, "onClick VideoView");
                if (videoView.isPlaying()) {
                    if (videoView != null amp;amp; videoView.canPause()) {
                        videoView.pause();
                        Log.d(TAG, "Pause video: "   videoURI);
                    }
                    assert videoView != null;
                    currentPosition = videoView.getCurrentPosition();
                } else {
                    if (currentPosition >= 0){
                        videoView.seekTo(currentPosition);
                        if (videoView != null) {
                            videoView.start();
                            Log.d(TAG, "Playing video:"   videoURI   " duration : "   videoView.getDuration());
                        }
                    }
                }
            }
        });

    }

    private Uri getMedia(String videoSource) {
        if (URLUtil.isValidUrl(videoSource)) {
            return Uri.parse(videoSource);
        }
        return Uri.parse(videoSource);
    }
  }
  
  • Моя проблема в том, что при запуске приложения может воспроизводиться первое видео в списке
    обычно, но когда я прокручиваю вниз до следующего видео, оно не может воспроизводиться
    видео, просто черный экран, хотя я могу видеть в журнале отладки
    «Воспроизведение видео: …..». И он выполняет странное поведение, когда
    прокручивая вверх и вниз, некоторое время можно воспроизводить видео, большая часть
    время не может.

Я еще ничего не понял, у вас есть какие-нибудь идеи? Или вы можете дать мне эквивалентное решение для этого amtter?
Спасибо!

Комментарии:

1. Я обнаружил это из журнала отладки при прокрутке до следующего видео, оба VideoView из двух VideoPreviewFragment , которые содержат проигрыватель, отсоединены от окна, поэтому видео 2nd не может воспроизводиться и отображается только черный экран. Я проверяю это, добавляя videoView.addOnAttachStateChangeListener . Но я не понимаю, почему это так. Это должно быть 1-е VideoView отсоединенное и 2-е VideoView прикрепленное к окну. Можете ли вы просветить меня по этому поводу.

2. И при прокрутке назад к 1-му видео оба VideoView из двух проигрывателей подключены к окну. Итак, если я перейду к 3-му видео, а затем вернусь к 2-му видео, его можно воспроизвести. Какой странный