5

別のスレッドで描画を実装する最初のライブ壁紙を作成しました。これで、仕事をする WallpaperService と WallpaperPainter ができました。問題は、一部のデバイスIllegalArgumentExceptionで inunlockCanvasAndPostメソッドを取得していることです (Samsung Note がその 1 つです)。見つけたすべての推奨事項を読みましたが、そのバグを修正できませんでした。サーフェスが破棄されたときに呼び出されるように見えるunlockCanvasAndPostため、キャンバスは無効です。コードの重要な部分は次のとおりです。

壁紙サービスでは:

    @Override
    public void onSurfaceChanged(SurfaceHolder holder, int format, int width,
            int height) {
        super.onSurfaceChanged(holder, format, width, height);
        painting.setSurfaceSize(width, height);
    }

    @Override
    public void onSurfaceCreated(SurfaceHolder holder) {
        super.onSurfaceCreated(holder);
        painting.start();
    }

    @Override
    public void onSurfaceDestroyed(SurfaceHolder holder) {
        boolean retry = true;
        painting.stopPainting();
        while (retry) {
            try {
                painting.join();
                retry = false;
            } catch (InterruptedException e) { }
        }
        super.onSurfaceDestroyed(holder);
    }

塗装スレッドで:

public void stopPainting() {
    this.run = false;
    synchronized(this) {
        this.notify();
    }
}

public void run() {
    this.run = true;
    Canvas c = null;
    while (run) {
        try {
            synchronized (this) {
                Thread.sleep(50);
                c = this.surfaceHolder.lockCanvas();
                doDraw(c);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (c != null) {
                this.surfaceHolder.unlockCanvasAndPost(c); // << -- HERE IS THE PROBLEM
            }
        }
        // if pause...
        synchronized (this) {
            if (wait) {
                try {
                    wait();
                } catch (Exception e) { }
            }
        }
    }
}

誰が私が間違っているのか手がかりを教えてもらえますか? 私はJavaとAndroidの両方が初めてです。

4

4 に答える 4

2

エラーがUnlockAndPost Failedの場合は、バッファーのロックを解除していないことを意味します。this.surfaceHolder.unlockCanvasAndPost(c);
あなたが追加することができた後
this.surfaceHolder.lockCanvas();
(私の貧弱な英語力で申し訳ありません)

于 2013-03-08T06:25:44.877 に答える
1

決定的な問題は見当たりませんが、ここにいくつかの考えがあります。

  • ロックされていないキャンバスのロックを解除する可能性があります。c = null;ループの一番上に設定します。そうしないと、次回ループを介してwhile前の値のロックが解除されます。c

    while (run) {
        Canvas c = null;
        ...
    
  • 複数のスレッドからアクセスさrunれるため、フィールドにとしてマークを付ける必要があります。volatile

  • ブロックThread.sleep(...)内を呼び出さないでください。synchronized他のスレッドを不必要にブロックするため、これは非常に悪い習慣です。

  • 少なくとも例外をログに記録するようにしてください。に細心の注意を払ってくださいcatch (Exception e) {}。それはあなたの問題を隠すことだけです。

  • ループのjoin()内側で行うことにはあまり意味がありません。whileスレッドが中断された場合は、ペイントスレッドを中断して終了する必要があります。

  • あなたは眠っていて待っているので睡眠を取り除いて次のようなことをする方が理にかなっています:

    try {
       synchronized (this) {
           if (wait) {
              wait();
           else {
              wait(50);
           }
       }
    } catch (Exception e) {
       e.printStackTrace();
    }
    
于 2012-10-10T13:15:59.163 に答える
1

ライブ壁紙にも同じ問題がありました。Nexus 5 エミュレーターでは正常に動作しますが、Nexus 10 エミュレーターで実行すると、アプリがロードされた瞬間にクラッシュします。

エミュレータのデフォルトのスキンの解像度が間違っていることが問題の原因であることがわかりました。スキンを「スキンなし」に変更したら、クラッシュしなくなりました。

不適切な解像度のスキンを修正する方法の詳細については、 Android Studio - タブレット エミュレーターが正しい解像度を表示しないを参照してください。

于 2015-09-21T14:39:01.433 に答える