2013-03-13 40 views
2

我目前在從不在我的主用戶界面上的線程繪製自定義SurfaceView時遇到問題。此SurfaceView佔用整個屏幕(全屏Galaxy S3),並且必須從多個來源更新。如何使用單獨的線程部分重繪自定義SurfaceView而不會丟失先前的編輯?

問題是自定義SurfaceView不會保存UI更新之間的更改。

自定義SurfaceView類被定義在使用它的活動中,並且在自定義SurfaceView類中定義了定期檢查更新的線程(我們稱之爲DrawingThread)。我已經做了類似於this tutorial

另一個外部線程正在更新必須對UI進行的更改列表。 DrawingThread每50ms左右檢查一次該列表,如果列表不爲空,則計算一個必須重繪的矩形。

// Thread waits for change request to UI or kill order 
// Build Rect at point of Touch 
try { 
    Canvas = _surfaceHolder.lockCanvas(Rect); 
    synchronized (_surfaceHolder) { 
     postInvalidate(); //Calls custom SurfaceView's onDraw() with the correct Canvas 
    } 
} finally { 
    if (Canvas != null) { 
     _surfaceHolder.unlockCanvasAndPost(Canvas); 
    } 
} 
// Loop 

onDraw()自定義SurfaceView方法如下:

@Override 
public void onDraw(Canvas canvas) { 
    // Initialize vars for rectangle 
    Paint.setStyle(Style.FILL); 

    for (MapChanges change : ExternalClass.getMapChanges()) { 
     // Build Rect at point of Touch 
     // Select Color for Paint 
     canvas.drawRect(Rect, Paint); 
     ExternalClass.removeMapChange(change); //Thread safe 
    } 
} 

這完美的作品,除了一個事實,即它是忘記從以前onDraw()通話的變化。我目前正在使用OnTouchListener進行測試。

代碼的程序,我的理解是:

  • 觸摸增加了對UI在ExternalClass列表中的更改請求。
  • DrawingThread看到列表不再爲空,安全地抓住畫布,並且postInvalidates()調用自定義SurfaceViewonDraw()
  • onDraw()更新UI並從ExternalClass中刪除更改請求。
  • DrawingThread發帖Canvas並返回等待。

我的預期行爲是我會連續觸摸在屏幕上累積點。相反,每次觸摸都會清除屏幕,讓我留下背景,並在上次觸摸屏幕時留下一個點。

我覺得這很容易混淆,因爲lockCanvas(Rect)明確提到它會通過指定「髒」部分來保存鎖之間的更改。 Google搜索讓我相信大多數用戶會發現相反的問題:他們希望重繪View,但必須手動更新每次更新。

爲什麼程序從頭開始繪製一個乾淨的SurfaceView每個UI更新,儘管我指定了一個「髒」部分來重繪?

毫無疑問,有人會引用我到this previously answered question,程序員被建議使用位圖。我試圖避免這種情況,這是因爲我對此有多新,以及我的願望是不能處理大量內存(更新UI僅僅是我的代碼的一小部分)。直接在View上使用簡單的形狀對我來說很理想。此外,它作爲解決方法呈現。這是Android API的一個缺陷嗎?

已經在這裏搜索和Google幾個小時了。希望我沒有錯過任何明顯的東西。

回答

0

我設法通過將OnDraw()排除在等式之外找到解決方法。新DrawingPanel如下:

class DrawingPanel extends SurfaceView implements Runnable, SurfaceHolder.Callback { 

    Thread thread = null; 
    SurfaceHolder surfaceHolder; 
    volatile boolean running = false; 

    private Paint myPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 
    Random random; 

    public DrawingPanel(Context context) { 
     super(context); 
     getHolder().addCallback(this); 

     surfaceHolder = getHolder(); 
    } 

    @Override 
    public void surfaceChanged(SurfaceHolder holder, int format, int width, 
     int height) { 


    } 

    @Override 
    public void surfaceCreated(SurfaceHolder holder) {   
     setWillNotDraw(false); //Allows us to use invalidate() to call onDraw() 

     if (!running) { 
      running = true; 
      thread = new Thread(this); 
      thread.start(); 
     } 
    } 

    @Override 
    public void surfaceDestroyed(SurfaceHolder holder) { 
     try { 
      running = false; //Tells thread to stop 
      thread.join();  //Removes thread from mem. 
     } catch (InterruptedException e) {} 
    } 

    @Override 
    public void run() { 
     Canvas canvas; 
     Rect myRect = new Rect(); 
     boolean firstRun = true; 

     ChangeRequest ChangeReq; 

     myPaint.setStyle(Style.FILL); 

     while(running) { 
      try { 
       Thread.sleep(50); 
      } catch (Exception e) {} 

      canvas = null; 

      ChangeReq = getUIChangeRequests(); 

      if (!ChangeReq.isEmpty() || (firstRun)) {     
       if(surfaceHolder.getSurface().isValid()) { 
        if (!firstRun) { 

         // Calculate dirty space for editing 
         x = ChangeReq.getX(); 
         y = ChangeReq.getY(); 

         try { 
          myRect.set(x*RectSize, y*RectSize, x*RectSize + RectSize, y*RectSize + RectSize); 
          myPaint.setColor(Color.RED); 

          canvas = surfaceHolder.lockCanvas(myRect); 

          synchronized (surfaceHolder) { 
           // Draw 
           canvas.drawRect(myRect, myPaint); 

          } 

          // Remove ChangeRequest 
          ChangeReq.remove(); 

         } finally { 
          if (canvas != null) { 
           surfaceHolder.unlockCanvasAndPost(canvas); 
          } 
         } 
        } else { 
         try { 
          // Initialize canvas as all one color 
          myRect.set(0, 0, getWidth(), getHeight()); 
          myPaint.setColor(Color.DKGRAY); 

          canvas = surfaceHolder.lockCanvas(); 

          synchronized (surfaceHolder) { 
           //Draw 
           canvas.drawRect(myRect, myPaint); 
          } 

          firstRun = false; 
         } finally { 
          if (canvas != null) { 
           surfaceHolder.unlockCanvasAndPost(canvas); 
          } 
         } 
        } 
       } 
      } 
     } 
    } 
} 

這解決了我的畫的問題,但帶來了爲什麼我必須初始化使用surfaceHolder.lockCanvas();才把我能夠使用surfaceHolder.lockCanvas(Rect);我會問這一個問題得出一個有趣的問題。

相關問題