2011-06-28 31 views
5

Tôi đang cố triển khai SurfaceView, gọi phương thức onDraw() từ số Thread, dựa trên this tutorial. Ứng dụng của tôi đang cung cấp ANR sau khi tôi bắt đầu chạy mã bên dưới.tại sao runnable của tôi cho ANR?

Tôi đã thử implementing Runnable, thay vì mở rộng Thread nhưng vẫn cung cấp ANR.

Theo như tôi biết there's nothing else running trên ứng dụng khi ANR xảy ra. (ANR chỉ bắt đầu xảy ra khi tôi thêm mã này :)

package com.thunderrabbit.run; 

import android.graphics.Canvas; 
import android.view.SurfaceHolder; 

public class MainThread extends Thread { 
    private final String TAG = this.getClass().getSimpleName(); 

    // desired fps 
    private final static int MAX_FPS = 50; 
    // maximum number of frames to be skipped 
    private final static int MAX_FRAME_SKIPS = 5; 
    // the frame period 
    private final static int FRAME_PERIOD = 1000/MAX_FPS; 

    private SurfaceHolder surfaceHolder; 
    private PageGLSurfaceView gamePanel; 
    private boolean running; // flag to hold game state 
    private Canvas canvas; 

    long beginTime;  // the time when the cycle begun 
    long timeDiff;  // the time it took for the cycle to execute 
    int sleepTime;  // ms to sleep (<0 if we're behind) 
    int framesSkipped; // number of frames being skipped 

    public MainThread(SurfaceHolder surfaceHolder, MySurfaceView gamePanel) { 
     super(); 
     this.surfaceHolder = surfaceHolder; 
     this.gamePanel = gamePanel; 
    } 

    public void setRunning(boolean running) { 
     this.running = running; 
    } 

    @Override 
    public void run() { 
     sleepTime = 0; 
     while(running) 
     { 
      canvas = null; 
      try 
      { 
       synchronized (surfaceHolder) 
       { 
        canvas = surfaceHolder.lockCanvas(); 
        beginTime = System.currentTimeMillis(); 
            // resetting the frames skipped 
        framesSkipped = 0; 
        // update game state 
        this.gamePanel.update(); 
        // render state to the screen 
        // draws the canvas on the panel 
        this.gamePanel.render(canvas); 
        // calculate how long did the cycle take 
        timeDiff = System.currentTimeMillis() - beginTime; 
        // calculate sleep time 
        sleepTime = (int)(FRAME_PERIOD - timeDiff); 

        if (sleepTime > 0) { 
         // if sleepTime > 0 we're OK 
         try { 
          // send the thread to sleep for a short period 
          // very useful for battery saving 
          Thread.sleep(sleepTime); 
         } catch (InterruptedException e) {} 
        } 

        while (sleepTime < 0 && framesSkipped < MAX_FRAME_SKIPS) { 
         // we need to catch up 
         // update without rendering 
         this.gamePanel.update(); 
         // add frame period to check if in next frame 
         sleepTime += FRAME_PERIOD; 
         framesSkipped++; 
        } 
        beginTime = System.currentTimeMillis(); 
        gamePanel.onDraw(canvas); 
       } 
      } 
      finally 
      { 
       if (canvas != null) 
       { 
        surfaceHolder.unlockCanvasAndPost(canvas); 
       } 
      } 
      // update game state 
      // render state to the screen 
     } 
     DebugLog.d(TAG, "Game loop executed "); 
    } 
} 

Điều gì gây ra ANR? Tôi có nên triển khai Runnable hoặc mở rộng Thread theo cách khác không?

+0

Nếu thread UI bị chặn trong hơn một vài giây người dùng sẽ được trình bày với các khét tiếng "ứng dụng không phản hồi" (ANR) hộp thoại. Bạn có biết về "Activity.runOnUiThread (Runnable)" không? Tôi nghĩ rằng đây sẽ là giải pháp của bạn. –

+0

Bạn có thể đăng Logcat không? –

+0

@Balaji Tôi đã thấy runOnUiThread, nhưng quên nó trong trường hợp này. Ngoài ra, xin lỗi tôi đã không thể đăng đầu ra LogCat; Tôi về cơ bản đã giải quyết nó trước khi gây ra vấn đề một lần nữa. :-) –

Trả lời

1

gamePanel kéo dài từ SurfaceView và nhận thông tin nhập của bạn (qua onTouchEvent()). Nói cách khác, chuỗi giao diện người dùng của bạn. Khi bạn đang gọi gamePanel.onDraw(canvas) Nó đang chặn (chờ phần cứng để vẽ trên canvas) và do đó bạn nhận được ANR.

Các MainThread dường như là chuỗi hiển thị (xem cách nó sở hữu canvas) và nó phải là hiển thị duy nhất. Lôgic trò chơi của bạn nên đi theo số MainGamePanel hoặc trong một chuỗi riêng biệt hoàn toàn.

Vì vậy, lý tưởng tôi sẽ có ba chủ đề:

  • một cho đầu vào (hoạt động chính mà dành phần lớn thời gian của mình không làm gì cả)
  • một cho logic trò chơi (a thread riêng biệt mà được cập nhật tất cả các thời gian)
  • một cho vẽ (công ty sở hữu bức tranh và đang thu hút tất cả các thời gian)
+0

Tôi gặp vấn đề tương tự nhưng chuỗi giao diện người dùng của tôi không phải là gamePanel Tôi đang sử dụng bố cục xml http://stackoverflow.com/questions/13128232/surfaceview-disappear-onresume –

1

Sử dụng Thread.sleep(...) chặn chuỗi. Nếu bạn chặn chuỗi giao diện người dùng, ứng dụng của bạn về cơ bản bị đóng băng và hệ điều hành sẽ coi ứng dụng đó không phản hồi. Thay vào đó, bạn nên xem xét sử dụng Bộ hẹn giờ. Ví dụ: herehere.

Về cơ bản thay vì ngủ chủ đề của bạn cho đến khi thực hiện tiếp theo, bạn đặt hẹn giờ để bạn có thể được gọi khi đến lúc thực hiện lại.

Các vấn đề liên quan