web-dev-qa-db-ja.com

フラグメント内のVideoViewにより、黒い画面がちらつく

AndroidアプリケーションはAndroid API 4.0で実行されています。アクティビティの1つには、画面を2つの部分に分割するレイアウトがあります。左側にはいくつかのボタンがある静的パーツ。右側には、押されたボタンに応じて対応するフラグメントに切り替わるFrameLayoutがあります。

問題:右側のフラグメントの1つに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を含むフラグメントに戻ると、ちらつきがなくなります。

21
Kenny

フラグメントの親アクティビティのレイアウトに0pxx 0pxのSurfaceViewを追加することで、これを修正できました。

<SurfaceView
        Android:layout_width="0px"
        Android:layout_height="0px" />
44
Kenny

KennyDsは正しいですが、SurfaceViewを非表示にすることをお勧めします。そうしないと、フラグメントをアニメーション化すると非常に奇妙な動作になり、アニメーション化されたフラグメントの代わりに黒い画面しか表示されません。幸い、この付随的な問題も簡単に修正できます。

<SurfaceView
    Android:layout_width="0px"
    Android:layout_height="0px"
    Android:visibility="gone" />
12
David

ゼロサイズのSurfaceViewを追加すると問題が解決する理由がわからない場合は、この質問をご覧ください SurfaceViewはロード時に黒く点滅します 。それはよく説明します。

Evosの回答から引用

サーフェスビューが最初にウィンドウに表示されると、プライベートIWindowSession.relayout(..)メソッドを呼び出してウィンドウのパラメータの変更を要求します。このメソッドは、新しいフレーム、ウィンドウ、およびウィンドウサーフェスを「提供」します。その瞬間に画面が点滅すると思います。解決策は非常に簡単です。ウィンドウにすでに適切なパラメータがある場合、ウィンドウのすべてのものが更新されず、画面が点滅しません。最も簡単な解決策は、アクティビティの最初のレイアウトに高さ0pxのプレーンSurfaceViewを追加することです。これにより、アクティビティが画面に表示される前にウィンドウが再作成され、2番目のレイアウトを設定すると、現在のパラメーターでウィンドウが引き続き使用されます。

そして、これがこの問題を解決するためのよりクリーンな方法です。setContentView()を呼び出す前にこれを呼び出します。これは、VideoViewを含むいくつかのフラグメントを使用してViewPagerでテストしたばかりで、サイズがゼロのSurfaceViewを追加するのと同じくらいうまく機能します。

getWindow().setFormat(PixelFormat.TRANSLUCENT);
4
Xavier Lin