Search code examples
javaandroidmultithreadingandroid-canvas

Reasons for my drawing thread to suddenly stop?


@Override
public void run() {
    super.run();

    final float timePerFrame = 1000 / Options.MAX_FPS;
    float timeDiff;
    while(!isInterrupted() && isRunning) {
        timeDiff = System.currentTimeMillis();
        mController.refresh();
        timeDiff = timePerFrame - (timeDiff - System.currentTimeMillis());

        try {
               Thread.sleep(Math.max(Math.round(timeDiff), 0));
        } catch(InterruptedException e) {
            // do nothing
            e.printStackTrace();
        }
    }
    Log.e("GameThread", "Thread dead.");
}

This is what my thread is basically doing.

Options.MAX_FPS = 30;

To limit the frames per second, to have some sort of sleeping time between each refresh. The refresh method looks like this:

public synchronized void refresh() { int mRotation = Math.round((360 + ((-1)*mAccelerometer[0] * 4.5f)) % 360); mObject.setRotation(mRotation);

    // get canvas from surfaceview
    if(mSurfaceHolder != null) {
        // do all calculations.
        if(Looper.myLooper() == Looper.getMainLooper()) {
            log("on main thread!");
        } else {
            log("Not on main thread");
        }


        Canvas mCanvas = mSurfaceHolder.lockCanvas();
        if (mCanvas != null) {
            // shift x offset
            mScreenWidth = mCanvas.getWidth();
            mScreenHeight = mCanvas.getHeight();

            // draw black background, clear everything.
            mCanvas.drawRect(new Rect(0,0,mScreenWidth, mScreenHeight), mBlackPaint);

            // shift & draw all viewobjects if still visible

            for(ViewObject view: mViewObjectList.toArray(new ViewObject[mViewObjectList.size()])) {
                view.shiftX(-1 * Options.Gameplay.Environment.MOVING_SPEED);
                if(view.getX() + view.getWidth() < 0) {
                    mViewObjectList.remove(view);
                }
                if(view.getCurrentBitmap() != null)
                    mCanvas.drawBitmap(view.getCurrentBitmap(), new Rect(0,0,view.getCurrentBitmap().getWidth(), view.getCurrentBitmap().getHeight()), new Rect(view.getX(), view.getY(), view.getX()+ view.getWidth(), view.getY()+view.getHeight()), new Paint());

                view.nextFrame();
            }

            // draw object
            final Bitmap sBitmap = mObject.getCurrentBitmap();
            mObject.nextFrame();
            if(sBitmap != null) {
                mCanvas.drawBitmap(sBitmap, new Rect(0, 0, sBitmap.getWidth(), sBitmap.getHeight()), new Rect(mObject.getX(), mObject.getY(), sBitmap.getWidth(), sBitmap.getHeight()), new Paint());
            } else log("bitmap = null!");
        }

        mSurfaceHolder.unlockCanvasAndPost(mCanvas);
    }
}

The thread keeps running for some time, background elements are being drawn (even though my rotation does not work quite yet, but that's another story..), the background "seems" to move (like a side-scroller), but at some random point in time, without any ADB LogCat messages (not limited to the App but the whole LogCat output) - the thread simply stops. No more drawing. Nothing. I am not calling interrupt or setting isRunning to false, as the "Thread dead." message is not written into LogCat as well.. I do not know what's happening. Thanks for your help.


Solution

  • You have:

    timeDiff = System.currentTimeMillis();
    // refresh, which takes some time I guess
    timeDiff = timePerFrame - (timeDiff - System.currentTimeMillis());
    

    so System.currentTimeMillis() will be later and therefore bigger than timeDiff. The term in brackets will be negative - so you will be adding onto the timePerFrame and timeDiff will grow not reduce.