3

アプリケーション内のランダムなポイントで断続的に一時停止しているスレッド (CanvasThread) に問題があります。アプリ内の他のすべての機能は引き続き必要に応じて機能します。何らかの理由でランダムにブロックされ、画面に新しいものを描画しないのはこのスレッドだけです。Surface.lockCanvasNative() がブロックの前に呼び出される最後の関数のようで、最初の関数がブロックの後に返されることに気付きました。そのようなパターンで:

Surface.lockCanvasNative (Landroid/graphics/Rect)Landroid/graphics/Canvas; @ 26,560 msec  ____
Surface.lockCanvasNative (Landroid/graphics/Rect)Landroid/graphics/Canvas; @ 40,471 msec  ____|

Surface.lockCanvasNative (Landroid/graphics/Rect)Landroid/graphics/Canvas; @ 40,629 msec  ____
Surface.lockCanvasNative (Landroid/graphics/Rect)Landroid/graphics/Canvas; @ 54,516 msec  ____|

これは、以下の traceview で明らかです。 凍結したスレッドの traceview

CanvasThread.run()それが役立つ場合、私は以下を使用しています:

@Override
public void run() {

    boolean tellRendererSurfaceChanged = true;

    /*
     * This is our main activity thread's loop, we go until
     * asked to quit.
     */
    while (!mDone) {
        /*
         *  Update the asynchronous state (window size)
         */
        int w;
        int h;
        synchronized (this) {
            // If the user has set a runnable to run in this thread,
            // execute it and record the amount of time it takes to 
            // run.
            if (mEvent != null) {
                mEvent.run();
            }

            if(needToWait()) {
                while (needToWait()) {
                    try {
                        wait();
                    } catch (InterruptedException e) {

                    }
                }
            }
            if (mDone) {
                break;
            }
            tellRendererSurfaceChanged = mSizeChanged;
            w = mWidth;
            h = mHeight;
            mSizeChanged = false;
        }


        if (tellRendererSurfaceChanged) {
            mRenderer.sizeChanged(w, h);
            tellRendererSurfaceChanged = false;
        }

        if ((w > 0) && (h > 0)) {
            // Get ready to draw.
            // We record both lockCanvas() and unlockCanvasAndPost()
            // as part of "page flip" time because either may block
            // until the previous frame is complete.

            Canvas canvas = mSurfaceHolder.lockCanvas();

            if (canvas != null) {
                // Draw a frame!
                mRenderer.drawFrame(canvas);                        
                mSurfaceHolder.unlockCanvasAndPost(canvas);

                //CanvasTestActivity._isAsyncGoTime = true;    
            }
            else{
                Log.v("CanvasSurfaceView.CanvasThread", "canvas == null");
            }
        }
    }
}

他に役立つ情報があれば教えてください。この時点でスレッドがブロックされている理由についての手がかりを探しているだけですか? 事前に助けてくれてありがとう!

それ以来、ブロックを絞り込んで、mSurfaceHolder.unlockCanvasAndPost(canvas);この呼び出しの前後にログを挿入しましたが、アプリがフリーズした後はログが記録されません。ただし、前のログは、このスレッドで最後にログに記録されたイベントです。これらのインスタンスのログも投入したため、null キャンバスを一時停止したり使用したりすることはありません。アプリが完了するまで一度もログに記録されません。

4

2 に答える 2

3

それ以来、私は自分の問題を理解しました。理由はわかりませんが、誤って以前の asyncTask() を完全にコメントアウトするのを忘れていたため、2 つがほぼ同じタスクを実行しており、明らかに同じ変数などでそうするのに苦労していました。ご指摘ありがとうございますが、私の側の単なる不注意な間違いだと思います。

于 2011-04-22T15:00:57.730 に答える
3

これが理由かどうかはわかりませんが、SurfaceHolder.lockCanvas() の下で、次のように警告されます。

Surface の準備ができていないときにこれを繰り返し呼び出すと (Callback.surfaceCreated の前または Callback.surfaceDestroyed の後)、CPU の消費を避けるために、呼び出しは低速に調整されます。

null が返されない場合、この関数は対応する unlockCanvasAndPost(Canvas) 呼び出しまで内部的にロックを保持し、SurfaceView が描画中にサーフェスを作成、破棄、または変更するのを防ぎます。これは、Callback.surfaceDestroyed で描画スレッドと特別な同期を行う必要がないため、Surface に直接アクセスするよりも便利です。

CPU がスロットリングを開始したときのしきい値がわかりません。キャンバスをリフレッシュしているスレッドはいくつですか?

ところで、

if(needToWait()) {
                while (needToWait()) {

冗長です

于 2011-04-21T16:56:15.093 に答える