9

Lunar Landerの例のように、基本的な部分が実装されている SurfaceView 拡張機能があります。つまりrun()、描画方法Threadは基本的に次のとおりです。

public void run() {
    while (mRun) {
        Canvas c;
            try {
                c = mSurfaceHolder.lockCanvas();
                synchronized (mSurfaceHolder) {
                    doDraw(c); // Main drawing method - not included in this code snippet
                }                                   
            } 

            finally {
                // do this in a finally so that if an exception is thrown
                // during the above, we don't leave the Surface in an
                // inconsistent state
                if (c != null) {
                    mSurfaceHolder.unlockCanvasAndPost(c);
                }
            }
        }
    }
} 

そして、Thread表面が破壊されたときに適切に停止します:

public void surfaceDestroyed(SurfaceHolder holder) {
    // we have to tell thread to shut down & wait for it to finish, or else
    // it might touch the Surface after we return and explode
    boolean retry = true;
    thread.setRunning(false);
    while (retry) {
        try {
            thread.join();
            retry = false;
        } 
        catch (InterruptedException e) {
        }
    }
}

これまでに通常テストしたデバイス (HTC Desire、Desire HD、および Archos 101 で、記憶が正しければ OS 2.2 と 2.3.3 を搭載) では、上記の問題は発生していません。つまり、ユーザーが をバックアウトしActivityたり、上で別のActivity関数が呼び出されたりしたためにサーフェスが破棄された場合、 内のコードは、が返されるために が呼び出されないことsurfaceDestroyed()を常に保証します。mSurfaceHolder.lockCanvas()null

ただし、Android 4 / ICS を実行している新しい HTC One X で見つけた違いは、メソッドの呼び出し中surfaceDestroyed()(つまり、そのメソッド内のコードがまだ実行中) に、描画にからキャンバスThreadが与えられることです。もちろん、これはアプリケーションのクラッシュを引き起こします。私のOne Xでは、これは表面が破壊されるたびに発生します-電話の回転、バックアウトなどによるものです.nullmSurfaceHolder.lockCanvas()Activity

私はnon- until has really exitedmSurfaceHolder.lockCanvas()を返す必要があるという印象を受けていたので、これについて混乱しています。確かに、これは Javadoc が言うことです:null CanvassurfaceDestroyed()

This is called immediately before a surface is being destroyed. After returning from this call, you should no longer try to access this surface. If you have a rendering thread that directly accesses the surface, you must ensure that thread is no longer touching the Surface before returning from this function.

今のところ私の解決策は、 をチェックすることですnull。これはうまくいきます:

if(c != null){
    doDraw(c); // Main drawing method - not included in this code snippet
}

しかし、Android 4 / ICS で突然これをしなければならない理由はありますか?

4

2 に答える 2

0

小さな実験をしました。surfaceDestroyed()次のようなメソッドに通知フラグをいくつか入れます。

public void surfaceDestroyed(SurfaceHolder holder) {
Log.i("i","i have started");
...[the code]...
Log.i("i","i have finished");
}

私が見つけたのはnullPionterExceptionOccurs、最初のフラグの後、2 番目のフラグの前に発生するという事実です。あなたの質問に対する最も可能性のある回答は、古いビューに到達できるときにキャンバスをロックし、それに描画しますが、その間に画面が変化することです。したがって、キャンバスのロックを解除すると、結果を表示する場所がなくなり、エラーが発生します。

PS サンプル Android コードから Lunar Lander で少し遊んで、ゲームが動作している間に画面を回転させてみてください。エラーが発生するときは、背景のビットマップがどのように描画されようとしていたかを見てください。画面の向きが変わったことがわかりますが、プログラムは何も起こらなかったかのようにビットマップを描画しようとしました。

于 2013-03-06T12:44:39.520 に答える