android倒计时

本文探讨了在Android中实现倒计时的三种方法:Handler、Timer和CountDownTimer。Handler在CPU休眠时可能导致定时任务失效,而CountDownTimer在特定设置下可能出现计数不准确的问题。此外,还提到了在倒计时需求中如何确保锁屏状态下仍能正常运行。

Handler


通过调用Thread类的 start()方法来启动一个线程,这时此线程处于就绪(可运行)状态,但此时并没有运行,它需要CPU时间片。一旦得到CPU时间片,就会执行run()方法。run()的方法体称为线程体,它包含了要执行的这个线程的内容,run()方法运行结束,此线程也随即终止。
经过测试,这种倒计时方式锁屏之后20s左右就会失效(timer不会失效)
mHandler.postDelayed(new Runnable() {
    @Override
    public void run() {
        mHandler.postDelayed(this, 1000);
    }
}, 1000);



Timer

    一个Timer内部封装装了“一个Thread”和“一个TimerTask队列”,这个队列按照一定的方式将任务排队处理。封装的Thread在Timer的构造方法调用时被启动,这个Thread的run方法按照条件去循环这个TimerTask队列,然后调用TimerTask的run方法。 但是,如果CPU进入了休眠状态,那么这个thread将会因为失去CPU时间片而阻塞,从而造成我们需要的定时任务失效。

样例:自定义一个button,点击之后开启倒计时,并在button上显示剩余时间,同时要确保锁屏之后继续正常倒计时(handler锁屏会失效)。

创建一个TimeButton集成Button

public class TimeButton extends Button{

初始化定时器

private void initTimer(){
        timer = new Timer();
        task = new TimerTask() {
            @Override
            public void run() {
                mHandler.sendEmptyMessage(777);
            }
        };
    }

启动定时器

public void start(){
    initTimer();
    timer.schedule(task , 0 , 1000);//延迟0s,每隔1s执行一次run方法
    this.setText(cycle + "");
}
定期刷新Button的text

Handler mHandler = new Handler(){
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        switch (msg.what){
            case 777:
                cycle -= space;
                if(cycle > 0 ){
                    TimeButton.this.setText((cycle/1000) + "s");
                }else {
                    TimeButton.this.setText("重新获取");
                    onDestory();
                }
                break;
        }
    }
};

调用这个定时器:

/**
 * 进入后台保存当前的时间进度(当前activity进入后台调用)
 */
public void saveTime(long time){
    mapTime.put("lastTimeOld" , time);
    lastTimeOld = cycle;
}

/**
 * 重新设置timer的显示的时间(当前activity进入前台调用)
 */
public void setNowTime(){
    if(isStarted){
        Long lastTime = mapTime.get("lastTimeOld");
        int textTime = (int) (System.currentTimeMillis() - lastTime);
        if(textTime < lastTimeOld){
            cycle = lastTimeOld - textTime;
            TimeButton.this.setText((cycle/1000) + "s");
        }else {
            LogUtils.e("重新获取");
            TimeButton.this.setText("重新获取");
            onDestory();
            setClickable(true);
        }
    }
}

/**
 * 点击事件
 */
case R.id.bt_time:
    timeButton.setClickable(false);
    timeButton.setTime(100000 , 1000).start();

@Overrideprotected void onResume() { super.onResume(); timeButton.setNowTime();}@Overrideprotected void onStop() { super.onStop(); timeButton.saveTime(System.currentTimeMillis());}


CountDownTimer

这是Android自己封装的计时器,使用起来非常简单。但是经过测试,发现这种方式如果间隔设定为1s,每隔10s这个onTick()方法会少执行一次,及只执行了9次。


CountDownTimer timer = new CountDownTimer(20000 , 1000) {//参数(周期,间隔)
    //每隔时间间隔执行一次
    @Override
    public void onTick(long millisUntilFinished) {
        tv_number.setText(millisUntilFinished/1000 + "s");
    }
    //循环结束执行
    @Override
    public void onFinish() {
        tv_number.setText("倒计时完了");
    }
};

它的底层实现源码:

public CountDownTimer(long millisInFuture, long countDownInterval) {
    mMillisInFuture = millisInFuture;
    mCountdownInterval = countDownInterval;
}
public synchronized final CountDownTimer start() {
    mCancelled = false;
    if (mMillisInFuture <= 0) {
        onFinish();
        return this;
    }
    mStopTimeInFuture = SystemClock.elapsedRealtime() + mMillisInFuture;
    mHandler.sendMessage(mHandler.obtainMessage(MSG));
    return this;
}
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);
            }
        }
    }
};


AlarmManager

        AlarmManager将应用与服务分割开来后,使得应用程序开发者不用 关心具体的服务,而是直接通过AlarmManager来使用这种服务。这也许就是客户/服务模式的好处吧。

    当我们在开发android程序时,有些用户会使用service来管理一些后台的任务,如网络操作,或者间断处理数据等,这些用户需要在用户关闭程序,或者关闭屏幕后也能处理后台任务,可android手机为了节省电池使用,当用户关闭屏幕后,会将cpu置于休眠状态,当休眠状态启动,我们的服务就处于暂停状态了.为了斛决这个问题,android库里就提供了一个AlarmManager的库,AlarmManager是客户/服务模式的模式,也就是说AlarmManager是由系统来管理,而不是我们应用程序的一部分,也就是说AlarmManager是全局的,当我们的程序启用AlarmManager后,就给系统注册了一个服务,该服务会根据你设置的参数定时的向你的应用程序发送消息(注意,此消息以广播方式发送).

am = (AlarmManager)getSystemService(ALARM_SERVICE);
int hour = 28 * 60 * 1000;
long targetTime = System.currentTimeMillis() + hour; //其中SystemClock.elapsedRealtime()表示开机到现在的时间
Intent intent1 = new Intent(this , GetTokenCastReciver.class);
pi = PendingIntent.getBroadcast(this, 0, intent1, 0);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    am.setExact(AlarmManager.RTC_WAKEUP, targetTime, pi);
}else {
    am.set(AlarmManager.RTC_WAKEUP, targetTime, pi);
}
















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值