简体   繁体   中英

Why doesn't countdown timer work on standalone class which is not an activity?

I am trying to use countdowntimer in Android, following is a small testcode to understand its behaviour

    new CountDownTimer(30000, 1000) {

        public void onTick(long millisUntilFinished) {
            System.out.println("tick");
        }

        public void onFinish() {
            System.out.println("finish");
        }
    }.start();

    System.out.println("done");

If I place this snippet in MainActivity of my project it runs fine, but not in a standalone class. Why ?

Also, does countdown timer run on main thread itself, or it spawns another thread ?

Your code includes 2 parts:

    CountDownTimer cdt = new CountDownTimer(30000, 1000) {

    public void onTick(long millisUntilFinished) {
        System.out.println("tick");
    }

    public void onFinish() {
        System.out.println("finish");
    }
};

The first part is instantiating a CountDownTimer object, you can place this code any where, on any thread, because only object was created, it does nothing.

The second part is:

cdt.start();

You should notice that CountDownTimer must be start from Main Thread (call it from onCreate or onResume... of an Activity). So if you place your code in another Class, it is not the problem, you must sure that start() function called on Main Thread.

//Update:

You know, the onTick and onFinish function of CountDownTimer always is called on Main Thread. CountDownTimer will not run any thread.

It's its code:

public synchronized final CountDownTimer start() {
    mCancelled = false;
    if (mMillisInFuture <= 0) {
        onFinish();
        return this;
    }
    mStopTimeInFuture = SystemClock.elapsedRealtime() + mMillisInFuture;
    mHandler.sendMessage(mHandler.obtainMessage(MSG));
    return this;
}

Very simply, CountDownTimer will send a message by a Handler.

And this is Handler:

// handles counting down
private Handler mHandler = new Handler() {

    @Override
    public void handleMessage(Message msg) {

        synchronized (CountDownTimer.this) {
            if (mCancelled) {
                return;
            }

            final long millisLeft = mStopTimeInFuture - SystemClock.elapsedRealtime();

            if (millisLeft <= 0) {
                onFinish();
            } else if (millisLeft < mCountdownInterval) {
                // no tick, just delay until done
                sendMessageDelayed(obtainMessage(MSG), millisLeft);
            } else {
                long lastTickStart = SystemClock.elapsedRealtime();
                onTick(millisLeft);

                // take into account user's onTick taking time to execute
                long delay = lastTickStart + mCountdownInterval - SystemClock.elapsedRealtime();

                // special case: user's onTick took more than interval to
                // complete, skip to next interval
                while (delay < 0) delay += mCountdownInterval;

                sendMessageDelayed(obtainMessage(MSG), delay);
            }
        }
    }
};

The Handler will send a delay message for calling next onTick() or onFinish(). So it must use Main Thread (or Main Looper). If you want it run in a custom thread, reimplement it in your way :D

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM