2

SurfaceView を使用してマーキー フィーチャを作成していますが、SurfaceView の描画スレッドの実行が開始された後、UI スレッドがブロックされ、[戻る] または [メニュー] ボタンへのタッチがディスパッチされず、ANRが生成されることがあります。これは時々起こります。

SurfaceView での描画の開始が早すぎるためだと思います(もちろん、surfaceCreated()との間で描画が行われるようにしますsurfaceDestroyed())。描画スレッドは、何かが完全に初期化された後に開始する必要があると思います。

Thread.sleep(100)実際にCanvas返された byを使用しSurfaceHolder.lockCanvas()て描画を開始するコードの前に追加すると、問題はほとんどなくなりますが、それでも発生しますが、頻度は低くなります。キャンバスに実際に何かを描画する前に、描画スレッドを十分長くスリープ状態にすると、問題は二度と発生しません。

何かが完全に初期化されてから描画を開始する必要があるように見えますが、それが何であるかはわかりません。

この SurfaceView は、レイアウト ファイルに配置される通常の View として使用されます。以下は、サーフェスに描画するために使用されるコードです。

public void run() {
    try {
        // this is extremely crucial, without this line, surfaceView.lockCanvas() may
        // produce ANR from now and then. Looks like the reason is that we can not start
        // drawing on the surface too early
        Thread.sleep(100);
    } catch (Exception e) {}

    while (running) {
        Canvas canvas = null;
        try{

            long ts = System.currentTimeMillis();

            canvas = surfaceHolder.lockCanvas();
            if (canvas != null) {
                synchronized (surfaceHolder) {
                    doDraw(canvas);
                }

                ts = System.currentTimeMillis() - ts;
                if (ts < delayInterval) {
                    Thread.sleep(delayInterval - ts);
                }
            }

        } catch (InterruptedException e) {
            // do nothing
        } finally {
            if (canvas != null)
                surfaceHolder.unlockCanvasAndPost(canvas);
        }

    }
}
4

1 に答える 1

1

Thread.sleepとの間SurfaceHolder.lockCanvasで呼び出すべきではありませんSurfaceHolder.unlockCanvasAndPost。キャンバスのロックが解除された後にのみ呼び出す必要があります。

あなたのコード例では、キャンバスはほとんど常にロックされたままになり、飢餓が発生します。SurfaceFlinger がキャンバスを処理するための小さなウィンドウしかありません。そのため、このコードが失敗することがあり、そのため ANR エラーが散発的に発生していました。

于 2012-10-12T14:38:43.153 に答える