3

互換性をチェックするために、より高いAPIレベルでテストしたいアプリをプログラムしました。API 10(2.3.3)の場合、問題はありませんでしたが、API 15(4.0.3)でアプリを実行するとすぐに、アクティビティを終了したときに、SurfaceViewの1つでNullPointerExceptionが発生しました。問題は解決したと言わざるを得ませんが、実際に例外が発生した理由がわかりません。だから多分あなたは私に言うことができます。

API10で私のために働いたコードは次のとおりです。これはrun()-methodの一般的な構造です。

public void run() {
    while (mThreadActive) {
        c = null;
        try {
            c = mSurfaceHolder.lockCanvas(null);
            synchronized (mSurfaceHolder) {
                if(mState == 1) {
                    updateValues();
                    updateAnimation();
                }
                doDraw(c);
            }
        } finally {
            if (c != null) {
                mSurfaceHolder.unlockCanvasAndPost(c);
            }
        }
    }
}

アクティビティを終了するときのAPI15の場合:doDraw()-methodが「c」に書き込もうとしたときに発生した例外。cをチェックしたところ、nullであることがわかったので、当然のことながら例外が発生しました。mThreadActiveまた、falseに設定しても、while-loopがトリガーされることを確認しました。コードサンプルは次のとおりです。

public void run() {
    while (mThreadActive) {
        c = null;
        try {
            c = mSurfaceHolder.lockCanvas(null);
            synchronized (mSurfaceHolder) {
                if(mState == 1) {
                    updateValues();
                    updateAnimation();
                }

                if(!mThreadActive)    // so it really is!
                    Log.d("Thread", "mThreadActive is false!");

                if(c == null)   // so it is too!
                    Log.d("Thread", "c is null!");

                doDraw(c);   // error
            }
        } finally {
            if (c != null) {
                mSurfaceHolder.unlockCanvasAndPost(c);
            }
        }
    }
}

mThreadActive-ステートメントでチェックされた後になぜfalseになるのかは想像できますが、。のwhile後に「c」がnullになる理由はわかりませんmSurfaceHolder.lockCanvas(null)。コードがシーケンシャルに実行されていないようです。

c != nullさて、解決策はそれを利用する前にチェックするでしょう:

public void run() {
    while (mThreadActive) {
        c = null;
        try {
            c = mSurfaceHolder.lockCanvas(null);
            synchronized (mSurfaceHolder) {
                if(mState == 1) {
                    updateValues();
                    updateAnimation();
                }
                if(c != null) // prevent drawing on c if c doesnt exist.
                    doDraw(c);
            }
        } finally {
            if (c != null) {
                mSurfaceHolder.unlockCanvasAndPost(c);
            }
        }
    }
}

では、API 10では正常に機能するのに、なぜAPI15で例外が発生するのでしょうか。もう1つの面白い点は、同じ構造を持つ他のSurfaceViewがあることですが、これと比較すると、すべて正常に機能します。コードがシーケンシャルに実行されないのはなぜですか?エミュレーター(かなり遅い)でテストしているからですか?

ありがとうございました。

4

2 に答える 2

2

falsewhile()にもかかわらず、ループが進行しているように見えると述べています。マークされていますかmThreadActive?必要があるかもしれません。mThreadActivevolatile

また、lockCanvas(null)臭い。コードの残りの部分を確認できないため、何をしようとしているのか正確にはわかりません。nullに aを渡すことについて API は何と言っていますlockCanvasか? SurfaceHolder(そして、生のインスタンスまたはサブクラスについて話しているのでしょうか?)

の API 仕様は、次SurfaceHolder.lockCanvas()を返すことができることを示していることに注意してnullください。

サーフェスが作成されていないか、編集できない場合は null が返されます。通常、Surface がいつ使用可能になるかを確認するには、Callback.surfaceCreated を実装する必要があります。

SurfaceHolder.CallbackAPI を読むと、インターフェイスを実装してイベントに応答する必要があるように見えますsurfaceCreated()。これは実際には、キャンバスに書き込む準備ができたことを知らせるイベントです。

于 2012-05-12T12:10:52.020 に答える
0

電話をかけると、非常によく似た問題が発生します。

public void surfaceDestroyed(SurfaceHolder holder)  {
    isAttached = false;
    this.drawthread = null;
}

アプリケーションを終了して描画スレッドを停止すると(使用するwhileブール値isAttachedはfalseですが、そのwhileループ内の描画コードは実行されます)、終了時にnull例外が発生します。ショーストッパーではなく、本当に修正したいものです。ある種の解決策も考えif (canvas != null)ていましたが、もっと良い方法があるに違いないと思いました。

これがこのエラーの奇妙なことです-それは時々起こるだけです-そしてより速いデバイスではあまり起こりません。私の見方では、holder.lockCanvas()nullが返されるという問題があります。つまり、ブール値がfalseに設定される前にホルダーが破棄され、whileがスレッドの実行を停止する可能性があります。スレッドレースの問題?

Thread.join()whileブール値をnullにする前に使用した可能性のある解決策を見つけましたが、 holder.lockCanvas()nullを返すと、描画が完了する前にホルダーが破棄されるため、意味がなく、null例外が発生します。

私が考えることができる他の解決策は、戻るボタンメソッドをオーバーライドし、表面ビューを破棄する前にwhileブール値を強制的にnullにすることです(それが可能であれば)が、if (canvas != null)おそらくよりクリーンだと思います。聞きたがっている他のアイデアはありますか?

編集:他の場所ではテストしていませんが、API17を使用してエラーが発生します

于 2013-02-08T07:11:11.243 に答える