2

Hey everyone I am fairly new to the android/glass development so please correct me if I am wrong.

I tried to create a High Frequency Live Card which is fine. However when I close the app, the function surfaceDestroyed() did not get trigger and thread.quit() did not get called.

I tried looking into the sample project stopwatch/timer and apparently they did not stop the thread as well. According to the documentation, surfaceDestroyed gets called right before the surface is destroy but what is my surface? I also read something call surfaceview, are they the same thing? is surfaceview my customview or livecard?

https://developers.google.com/glass/develop/gdk/ui/live-cards#creating_high-frequency_live_cards

Appreciate any kind of help!!!

/ ***
  * LiveCardRender Class
*** /
public class LiveCardRender implements DirectRenderingCallback {
    private static final long FRAME_TIME_MILLIS = 33;
    private CustomView mCustomView;
    private SurfaceHolder mHolder;
    private boolean mPaused;
    private RenderThread mRenderThread;

    private class RenderThread extends Thread {
        private boolean mShouldRun;

        public RenderThread() {
            mShouldRun = true;
        }

        private synchronized boolean shouldRun() {
            return mShouldRun;
        }

        public synchronized void quit() {
            mShouldRun = false;
        }

        @Override
        public void run() {
            while (shouldRun()) {
                draw(mCustomView);
                SystemClock.sleep(FRAME_TIME_MILLIS);
            }
        }
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        mHolder = holder;
        updateRendering();
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        mHolder = null;
        updateRendering();
    }

    @Override
    public void renderingPaused(SurfaceHolder holder, boolean paused) {
        mPaused = paused;
        updateRendering();
    }

    private synchronized void updateRendering() {

        boolean shouldRender = (mHolder != null) && !mPaused;
        boolean rendering = mRenderThread != null;

        if (shouldRender != rendering) {
            if (shouldRender) {
                mRenderThread = new RenderThread();
                mRenderThread.start();
            } else {
                mRenderThread.quit();
                mRenderThread = null;
            }
        }
    }

    private void draw(View view) {

        Canvas canvas;
        try {
            canvas = mHolder.lockCanvas();
        } catch (Exception e) {
            return;
        }
        if (canvas != null) {
            view.draw(canvas);
            mHolder.unlockCanvasAndPost(canvas);
        }
    }
}

/ ***
  * LaunchService Class that uses LiveCardRender to update the live card
*** /
public class LaunchService extends Service {
    private static final String LIVE_CARD_TAG = "motion_card";
    private TimelineManager mTimelineManager;
    private LiveCard mLiveCard;
    private LiveCardRender mLiveCardRender;

    @Override
    public void onCreate() {
        mTimelineManager = TimelineManager.from(this);
    }

    public int onStartCommand(Intent intent, int flags, int startId) {
        if (mLiveCard == null) {
            mLiveCard = mTimelineManager.createLiveCard(LIVE_CARD_TAG);
            mLiveCardRender = new LiveCardRender(this);
            mLiveCard.setDirectRenderingEnabled(true);
            mLiveCard.getSurfaceHolder().addCallback(mLiveCardRender);
            mLiveCard.publish(PublishMode.REVEAL);
        }
        return START_STICKY;
    }

    @Override
    public void onDestroy(){
        if (mLiveCard != null && mLiveCard.isPublished()) {
            if (mLiveCardRender != null) {
                mLiveCard.getSurfaceHolder().removeCallback(mLiveCardRender);
            }
            mLiveCard.unpublish();
            mLiveCard = null;
        }
        super.onDestroy();
    }
}
Jacky So
  • 233
  • 5
  • 12
  • How do you close your app? The samples' rendering thread do get killed when the LiveCard gets unpublished: this only happens when the Service is stopped. – Alain Jan 24 '14 at 00:42
  • Mine doesnt. For example the google stopwatch sample, I putted a Log message in the draw(View view) function and even after I close the app with the menu option "stop". The Log message keep on going in LogCat. And the Log message inside surfaceDestroyed(SurfaceHolder holder) was never get called – Jacky So Jan 24 '14 at 03:01
  • Hum, this seems like a bug... Another way you could stop your rendering thread would be to manually call `onSurfaceDestroyed` when your Service's `onDestroyed` method is called. – Alain Jan 24 '14 at 16:49

1 Answers1

1

It looks like the bug is here, inside onDestroy:

if (mLiveCard != null && mLiveCard.isPublished()) {
    if (mLiveCardRender != null) {
        mLiveCard.getSurfaceHolder().removeCallback(mLiveCardRender);
    }
    mLiveCard.unpublish();

By removing the callback before the unpublish method is called, the system no longer knows whose surfaceDestroyed method to call when the card is removed afterwards. You can actually remove call to removeCallback entirely; it's unnecessary.

It looks like this is a bug in some of our samples that we missed as our APIs evolved. Thanks for catching it and we'll have them updated shortly!

Tony Allevato
  • 6,429
  • 1
  • 29
  • 34