web-dev-qa-db-ja.com

読み込み時にSurfaceViewが黒く点滅する

複雑な描画(AsyncTaskで実行)の描画を読み込むのに約2〜5秒かかる描画アプリがあります。ユーザーエクスペリエンスを向上させるために、この間、保存したPNGバージョンの図面をアプリディレクトリからImageViewとしてフラッシュし、読み込み中ProgressBarを呼び出すsetContentView()を表示しますActivityコンストラクタで:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent">
    <ImageView
    Android:id="@+id/flash"
    Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        Android:src="@color/note_bg_white"
        Android:contentDescription="@string/content_desc_flash_img"
        Android:focusable="false" />
<RelativeLayout
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        Android:paddingBottom="6dp"
        Android:paddingLeft="6dp"
    Android:paddingRight="6dp"
        Android:gravity="bottom|center_vertical">
        <ProgressBar 
            style="?android:attr/progressBarStyleHorizontal"
    Android:id="@+id/toolbar_progress"
    Android:layout_width="match_parent"
    Android:layout_height="18dp"
    Android:gravity="bottom|center_vertical" />
    </RelativeLayout>
</FrameLayout>

AsyncTaskが完了したら、新しいレイアウトでsetContentView()を再度呼び出します。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:id="@+id/layout"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:background="#ffffff">
    <com.my.package.DrawingCanvas
        Android:id="@+id/canvas"
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        Android:focusable="true"
        Android:background="#ffffff" />
</RelativeLayout>

シンプルなCanvasモデルを使用していたとき、これは完全に機能しました。カスタムのDrawingCanvas Viewは、ユーザーに表示される前に最初のonDraw()で画面に描画を描画するためです。 、しかし描画ループでSurfaceViewを使用すると、フラッシュされたレイアウトが表示され、描画が読み込まれると、約1秒間黒い画面が表示され、最後に新しいDrawingCanvasが表示されます。

理由は描画ループスレッドの起動時間に関連していると想定しており、onDraw()のオーバーライドをSurfaceViewに残し、それが呼び出されますが、 onDraw()で利用できるキャンバスはSurfaceViewに描画されないようです。上記のXMLで無地の背景を設定して、最低でも白い背景が表示されるようにしてみましたが、コードから設定したとしても、効果がないようです。

黒い画面で何が表示されているかについてのアドバイスや説明はありますか?

編集:

さて、onDraw()が同じキャンバスに描画していることを確認したので、私の描画操作をそのままにし、SurfaceViewの最初の表示で、ユーザーが通常のCanvas実装のようにこれらの描画を表示することを期待します。描画スレッドがスピンアップすると、キャンバスを上書きします。

ただし、描画スレッドの操作をクリアすると、onDraw()の結果は表示されますが、黒い画面が点滅した後も同じです。また、onDraw()オーバーライドを完全に削除しても、黒いフラッシュが表示され、XMLから白い背景のレイアウトが表示されます。

だから、何があっても、黒い画面が常に表示されます。おそらく、レイアウトを切り替える代わりに、すでにアクティブになっている既存の「フラッシュ」レイアウトを単に変更しない限り、どうですか?

EDIT2:

ViewStub を使用して、ノートが読み込まれた後、SurfaceViewを既存のビューに展開できるようにしましたが、同じ問題が引き続き適用されます。私が知ることができる限り、SurfaceViewコンストラクターとsurfaceCreated()の呼び出しの実行の間にかなりの遅延(〜200ms)がありますが、これが黒い画面が発生している場所であるか、または画面が描画されている理由がわかりません黒...

EDIT3:

私の今の最後の試みは、 SurfaceViewを透明にする にすることです。これと既存のレイアウトをそのままにして、ViewStubを介してそのレイアウトに単に追加することを組み合わせることで、実際に解決策が得られますが、それでも、SurfaceViewがロードされているときに、SurfaceViewが表示される前に画面が黒く点滅します。透明として。他に試してみたいアイデアがあれば、投稿してください。

32
Paul Mennega

黒い閃光の理由を見つけたと思います。私の場合、フラグメント内でSurfaceViewを使用しており、何らかのアクションの後でこのフラグメントをアクティビティに動的に追加しています。フラグメントをアクティビティに追加した瞬間、画面が黒く点滅します。 SurfaceViewソースのgrepcodeをチェックアウトしたところ、次のことがわかりました。サーフェスビューがウィンドウに最初に表示されると、プライベートIWindowSession.relayout(..)メソッドを呼び出してウィンドウのパラメーターの変更を要求します。このメソッドは、新しいフレーム、ウィンドウ、およびウィンドウサーフェスを「提供」します。その瞬間に画面が右に点滅すると思います。

解決策は非常に単純です。ウィンドウにすでに適切なパラメーターがある場合、ウィンドウの内容がすべて更新されず、画面が点滅しません。最も簡単な解決策は、0pxプレーンサーフェスの高さをアクティビティの最初のレイアウトに合わせます。これにより、アクティビティが画面に表示される前にウィンドウが再作成され、2番目のレイアウトを設定すると、現在のパラメーターでウィンドウを使用し続けます。これがお役に立てば幸いです。

[〜#〜] update [〜#〜]:数年後、この動作はまだ残っているようです。 SurfaceViewの代わりに TextureView を使用することをお勧めします。これは文字通り、この副作用のない同じもののより新しい実装であり、移動するときに(たとえば、ScrollView、ViewPager、RecyclerViewなど内で)黒の背景の問題がありません。

147
Evos

2つの個別のレイアウトではこれを行いません。

ルート要素をRelativeLayoutにしてから、SurfaceViewとImageViewをその兄弟の子にします。スレッディングなどで何が起こっても、ImageViewは、SurfaceViewの上に完全に不透明に描画される必要があるため、フラッシュが発生しません。

ワーカースレッドが描画を読み込み、SurfaceViewがそれ自体を描画できるようになったら、ビュー階層から進行状況バーとImageViewを削除します。

5
Reuben Scratton

私が知る限り、サーフェスビューは一度にすべてを描画した後で完全なビューを表示するため、サーフェスビューに重いコードを描画していると思います。最初にサーフェスビューのonDraw()メソッドに移動し、次にキャンバスの背景に設定してから、その黒い画面を回避するために強制的に無効化を呼び出すことをお勧めします。この強制的な無効化が1回だけ呼び出されるようにするための条件を追加します。

2
Tofeeq Ahmad

フラグメントでNavigationDrawerを使用すると、Evosソリューションは機能しなくなります!
フラグメントの代わりにアクティビティでNavigationDrawerを使用してみてください。これは100%役立ちます

アクティビティでNavDrawerを実装する方法: link
別の役立つ リンク 。 (SurfaceViewの場合、SlidingMenuの上に描画されます)

1

SurfaceViewのSurfaceのコンテンツを完全に描画して投稿するまで、onSurfaceChanged()が返らないことを確認する必要があります。

1
hackbod

私は同じ問題に直面していますが、この答えに感謝します

より面倒な方法はありますが、getWindow()。setFormat(PixelFormat.TRANSLUCENT);を置くだけです。ホストアクティビティのonCreate()コールバックで、setContentView()を呼び出す前に。

0
tej shah

"onDraw()で使用可能なキャンバスがSurfaceViewに描画されていないようです"-サーフェスビューの2番目(または3番目...)のインスタンスを作成しなくてもよろしいですか?そして、それらのいくつかは黒く、一瞬表示される可能性があります。ここにはコードが表示されないので、はっきりとはわかりませんが、アプリケーションに含まれている場合は、最初にこのエラーを確認します。

0
Gangnus

CrazyOrrの解決策は私にとってはうまくいきましたが、それはEvosによるトップアンサーのコメントの奥深くにあったので、ここに再びあります:

より面倒な方法はありますが、getWindow()。setFormat(PixelFormat.TRANSLUCENT);を置くだけです。ホストアクティビティのonCreate()コールバックで、setContentView()を呼び出す前に。 – CrazyOrr 2016年5月5日7:29

単に置く

_getWindow().setFormat(PixelFormat.TRANSLUCENT); 
_

アクティビティのonCreate()でうまくいきました。

0
Björn Kechel