2012-10-06 13 views
5

私は最初のライブ壁紙を作成し、別のスレッドで描画しました。今、私はWallpaperServiceと私のWallpaperPainterを持っています。問題は、デバイスの一部でをunlockCanvasAndPostメソッドに取得していることです(Samsung Noteがその1つです)。私は見つけることができるすべての勧告を読みましたが、そのバグを修正できませんでした。サーフェスが破棄されたときにキャンバスが無効になるとunlockCanvasAndPostが呼び出されたようです。ここでは、コードの重要な部分である:壁紙サービスでunlockCanvasAndPostのIllegalArgumentException(アンドロイドライブ壁紙)

: 絵画のスレッドで

@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の両方に新しいです。

答えて

1

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

  • ロックされていないキャンバスのロックを解除する可能性があります。私はあなたのwhileループの先頭にc = null;を設定します。さもなければ、前回の値cは次回にループを解除します。

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

  • ブロック​​の中にThread.sleep(...)をコールしないでください。他のスレッドを不必要にブロックするので、これは非常に悪いことです。

  • 少なくともログに例外が記録されていることを確認してください。 catch (Exception e) {}には十分注意してください。すべてのことがあなたの問題を隠すだけです。

  • ループ内にjoin()を実行することに多大な影響はありません。ループはwhileです。スレッドが中断した場合は、ペイントスレッドを中断して終了する必要があります。

  • あなたは両方眠っ待っているので、それは睡眠を削除し、同じような何かをするより理にかなって:エラーがある場合は

    try { 
        synchronized (this) { 
         if (wait) { 
          wait(); 
         else { 
          wait(50); 
         } 
        } 
    } catch (Exception e) { 
        e.printStackTrace(); 
    } 
    
2

UnlockAndPostはを失敗し、それが意味それはバッファをロック解除しませんでした。 this.surfaceHolder.unlockCanvasAndPost(c);
した後、あなたは、壁紙のプレビューを開くと

2

は、オブジェクトWallpaperServiceを作成し、さらにエンジンのインスタンスを作成します
this.surfaceHolder.lockCanvas();
(私の下手な英語能力のために申し訳ありません)を追加することができます。その後、ストリームは壁紙の描画を開始します。

「壁紙の設定」をクリックすると、WallpaperServiceの新しいインスタンスは作成されません。しかし、彼はonCreateEngine()メソッドを呼び出します。これはEngineの別の(2番目の)インスタンスを返します。どちらも独自のスレッドを実行します。

今、2つの競合スレッドがあります!したがって例外がスローされます。

バグを修正するために必要なのは、正しいメソッドonCreateEngine()を書くことだけです。

この置き換え:私は私のライブ壁紙と同じ問題を抱えていた

private SampleEngine engine; 

@Override 
public Engine onCreateEngine() { 

    if (engine!=null) { 
     engine.painting.stopPainting(); 
     engine = null; 
    } 
    engine = new SampleEngine(); 
    return engine; 
} 
1

:これまで

@Override 
public Engine onCreateEngine() { 
    return new SampleEngine(); 
} 

を。 Nexus 5エミュレータでは正常に動作しますが、Nexus 10エミュレータで実行すると、アプリが読み込まれるとクラッシュします。

エミュレータのデフォルトのスキンが間違った解像度を持つため、この問題が発生していることがわかりました。スキンを「スキンなし」に変更した後、もうクラッシュすることはありません。

間違った解像度で皮膚を修正する方法の詳細については、以下を参照してください。 Android Studio - Tablet emulator not showing correct resolution

関連する問題