2012-10-06 36 views
5

我已經創建了我的第一個活動壁紙在一個單獨的線程中實現繪圖。所以現在我有一個WallpaperService和我的WallpaperPainter誰做這項工作。問題是我在某些設備上使用unlockCanvasAndPost方法獲得IllegalArgumentException方法(Samsung Note是其中的一種)。我讀過所有我能找到的推薦,但無法修復這個錯誤。似乎unlockCanvasAndPost在表面被銷燬時調用,因此畫布無效。這裏是代碼的基本部分:IllegalArgumentException in unlockCanvasAndPost(android動態壁紙)

在壁紙服務:

@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) {}。所做的只是掩蓋你的問題。

  • while循環中執行join()沒有多大意義。如果你的線程中斷,你應該中斷繪畫線程並退出。

  • 既然你都睡等待,它會更有意義,除去睡覺和做一些事情,如:

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

如果錯誤是:UnlockAndPost失敗,這意味着它沒有解鎖緩衝區。 this.surfaceHolder.unlockCanvasAndPost(c);
後可以追加
this.surfaceHolder.lockCanvas();
(我那可憐的英語水平抱歉)

2

當您打開壁紙預覽,創建對象WallpaperService,並進一步創建引擎的實例。然後,流開始繪製牆紙。

然後,當你點擊「設置壁紙」 - 一個新的WallpaperService實例不會被創建。但是他調用了onCreateEngine()方法,該方法返回Engine的另一個(第二個)實例。其中也運行它自己的線程。

現在你有兩個競爭線程!所以他們導致拋出異常。

所有你需要做的修復bug - 就是在onCreateEngine()上寫一個正確的方法。

替換此:

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

這樣:

private SampleEngine engine; 

@Override 
public Engine onCreateEngine() { 

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

我與我的動態壁紙同樣的問題。在Nexus 5仿真器上運行良好,但是當我在Nexus 10仿真器上運行它時,會在應用加載時崩潰。

我發現問題是因爲模擬器的默認皮膚具有錯誤的分辨率。在我將皮膚改爲「無皮膚」之後,我再也沒有遇到這種情況。

有關如何解決與錯誤的分辨率的外觀的詳細信息,請參閱: Android Studio - Tablet emulator not showing correct resolution