VideoView внутри фрагмента вызывает мерцание черного экрана

У нас есть приложение для Android, работающее на Android API 4.0. Одно из действий имеет макет, который делит экран на 2 части. С левой стороны у нас есть статическая часть с некоторыми кнопками. С правой стороны у нас есть FrameLayout, который будет переключаться на соответствующий фрагмент в зависимости от нажатой кнопки.

Проблема. Один из фрагментов справа содержит VideoView. Когда пользователь нажимает кнопку, чтобы показать этот фрагмент, фрагмент отображается, и видео сразу же начинает воспроизводиться, однако: при рендеринге этого фрагмента весь экран мерцает черным, что очень раздражает.

Вот некоторый код класса VideoFragment:

public class VideoFragment extends Fragment {

    public VideoView videoView;

    private ExternalVideo mVideo;
    private boolean mVideoExists;
    private String mDestination;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mDestination = ApplicationParams.MEDIA_STORAGE_PATH + "videos/"
                + FilenameUtils.getBaseName(((DetailActivity)getActivity()).getProduct().getVideoUrl())
                + "."
                + FilenameUtils.getExtension(((DetailActivity) getActivity()).getProduct().getVideoUrl());

        File file = new File(mDestination);
        mVideoExists = file.exists() && file.isFile();
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view;

        if (mVideoExists) {
            getActivity().getWindow().setFormat(PixelFormat.TRANSLUCENT);
            view = inflater.inflate(R.layout.video, null);
            mVideo = new ExternalVideo(mDestination);

            videoView = (VideoView) view.findViewById(R.id.video_video);

            MediaController mediaController = new MediaController(getActivity());
            mediaController.setAnchorView(videoView);

            videoView.setMediaController(mediaController);
            videoView.setVideoPath(mVideo.getFullPath());
            videoView.requestFocus();
            videoView.setVisibility(View.VISIBLE);

            videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                public void onPrepared(MediaPlayer mp) {
                    videoView.start();

                }
            });
        } else {
            TextView textView = new TextView(getActivity());
            textView.setText(getActivity().getString(R.string.videofragment_video_coming_soon));
            textView.setPadding(50, 50, 50, 50);
            view = textView;
        }

        return view;
    }

}

Вот макет видеофрагмента:

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent">
    <VideoView android:id="@+id/video_video"
               android:layout_width="fill_parent"
               android:layout_alignParentRight="true"
               android:layout_alignParentLeft="true"
               android:layout_alignParentTop="true"
               android:layout_alignParentBottom="true"
               android:layout_height="fill_parent"/>
</RelativeLayout>

Кто-нибудь знает, что может быть причиной этой проблемы мерцания при рендеринге фрагмента, содержащего VideoView? Решение приветствуется!

EDIT1: Если я нажму на фрагмент, где находится VideoView, экран в начале мерцает. Когда я затем перехожу к другому фрагменту и возвращаюсь к тому, который содержит VideoView, мерцание исчезает.


person Kenny    schedule 18.07.2013    source источник
comment
Вы запускали свое приложение в эмуляторе?   -  person Tugrul    schedule 18.07.2013
comment
Запуск приложения на планшете Samsung Galaxy Tab 2 10.1   -  person Kenny    schedule 18.07.2013
comment
Попробуйте setAnchorView(videoView) на своем MediaController developer.android.com/reference/android/widget/< /а>   -  person Ken Wolf    schedule 18.07.2013
comment
@KenWolf Пробовал, и щелканье все еще сохраняется.   -  person Kenny    schedule 18.07.2013
comment
Хм, я не вижу ничего плохого в том, что вы написали. У меня есть приложения, которые без проблем отображают VideoViews во фрагментах, как вы описываете. Я хотел бы посмотреть, смогу ли я протестировать на другом устройстве или, в качестве альтернативы, также опубликовать код/макет вашего фрагмента.   -  person Ken Wolf    schedule 18.07.2013
comment
@KenWolf Та же проблема на Samsung Galaxy Tab 10.1. Я обновил свой вопрос полным классом VideoFragment.   -  person Kenny    schedule 18.07.2013
comment
Хорошо, последнее предположение, и я перестану забивать комментарии :) Попробуйте удалить следующие 3 строки: getActivity().getWindow().setFormat(PixelFormat.TRANSLUCENT); videoView.requestFocus(); и videoView.setVisibility(View.VISIBLE);   -  person Ken Wolf    schedule 18.07.2013
comment
@KenWolf Та же проблема все еще сохраняется :(   -  person Kenny    schedule 18.07.2013
comment
Добавлено Edit1 в вопрос   -  person Kenny    schedule 18.07.2013


Ответы (4)


Я смог исправить это, добавив 0px на 0px SurfaceView в макете родительской активности фрагмента:

<SurfaceView
        android:layout_width="0px"
        android:layout_height="0px" />
person Kenny    schedule 18.07.2013
comment
Я также сталкиваюсь с той же проблемой: когда я запускаю фрагмент видео, он сначала показывает BG (экран обоев), а затем показывает фрагмент видео. Я пытался использовать onPreparedListener(..), но тот же результат... есть идеи/предложения? - person CoDe; 29.10.2013
comment
Работал и для меня. Применяется также к классу активности - person Jake; 12.11.2013
comment
@Med AL В макете XML - person Kenny; 06.03.2015
comment
Да я знаю, но где именно? перед тегом VideoView? @KennyDs - person Mohamed ALOUANE; 12.03.2015
comment
@Nathan см. объяснение Ксавьера Линя ниже. - person Kenny; 16.06.2016

KennyDs прав, но лучше не забудьте скрыть SurfaceView, иначе у вас будет очень странное поведение, если вы будете анимировать фрагменты, тогда вы не увидите ничего, кроме черного экрана на месте анимированного фрагмента. К счастью, эту побочную проблему также легко решить:

<SurfaceView
    android:layout_width="0px"
    android:layout_height="0px"
    android:visibility="gone" />
person David    schedule 10.04.2014
comment
На Android 5.1 разницы нет. - person user2966445; 28.08.2016

Если вам интересно, почему добавление SurfaceView нулевого размера решает проблему, вы можете взглянуть на этот вопрос SurfaceView мигает черным цветом при загрузке . Это хорошо объясняет.

Цитата из ответа Эвоса

когда представление поверхности появляется в окне в первый раз, оно запрашивает изменение параметров окна, вызывая приватный метод IWindowSession.relayout(..). Этот метод «дает» вам новую рамку, окно и поверхность окна. Я думаю, что экран мигает прямо в этот момент. Решение довольно простое: если ваше окно уже имеет соответствующие параметры, оно не будет обновлять все содержимое окна, и экран не будет мигать. Самое простое решение — добавить обычный SurfaceView высотой 0 пикселей к первому макету вашей активности. Это воссоздает окно до того, как активность будет показана на экране, и когда вы установите второй макет, он просто продолжит использовать окно с текущими параметрами.

И вот более чистый способ решить эту проблему, вызовите его перед вызовом setContentView(), только что протестированный на моем ViewPager с некоторыми фрагментами, содержащими VideoView, он работает так же хорошо, как добавление SurfaceView нулевого размера:

getWindow().setFormat(PixelFormat.TRANSLUCENT);
person Xavier Lin    schedule 26.05.2016
comment
Эта единственная строка кода решила проблему. Спасибо - person Nizam; 14.07.2016
comment
Это не имеет значения для меня на Android 5.1. - person user2966445; 28.08.2016

Просто добавьте прозрачный цвет фона VideoView. Это решит проблему.

android:background="@color/transparent"
person Rohail Ahmad    schedule 10.09.2015