Android进阶——Android常见项目模块之倒计时、定时和延时的应用

引言

突然发现自己在博客中分了好多模块,每一个模块都还没能完整的总结完毕,ORZ,只能慢慢来,后面逐步完善吧。其实严格来说无论是定时、倒计时还是延时都是一类功能,只需我们灵活改变下逻辑即可。

一、Android倒计时器

实现倒计时器很很多方式:CountDownTimer借用Java中的Timer和TimerTask以及用Thread自己去实现等等,但是在Android中更多采用的是Android自己封装的CountDownTimer去实现。

1、CountDownTimer概述

CountDownTimer是一个轻量级的多线程机制,从源码中可以看到他是一个抽象类,本质是通过Handler实现线程之间的通信。由于CountDownTimer是抽象类不能直接通过new 构造实例,往往我们采用匿名类赋值初始化和构造子类实例两种方式来获取CountDownTimer对象,然后调用start方法开启倒计时即可

2、CountDownTimer的应用及注意事项

public class MainActivity extends AppCompatActivity{

    private MyCountDownTimer timer;
    private TextView textView;
    private long openTime= 20000L;
    private static final String TIMES="timer";
    private long leftTime=0L;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        init();
    }
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putLong(TIMES,leftTime);
    }

    @Override
    protected void onRestoreInstanceState(Bundle bundle){
        if(bundle!=null) {
            textView.setText(formatDuring(bundle.getLong(TIMES)));
        }
    }


    private void init(){
        getViews();
        textView.setText(formatDuring(openTime));
        timer=new MyCountDownTimer(openTime,1000);
        timer.start();
    }

    private void getViews(){
        textView= (TextView) findViewById(R.id.tv_delay_open);
    }

    //使用匿名类赋值的方式初始化
    private CountDownTimer countDownTimer=new CountDownTimer(openTime,1000) {
        @Override
        public void onTick(long l) {
            textView.setText(formatDuring(l));
            openTime=l;
            Log.e("CrazyMO", "onTick"+String.valueOf(l / 1000));
        }

        @Override
        public void onFinish() {
            Log.e("CrazyMO","OnFinish");
        }
    };

    private class MyCountDownTimer extends CountDownTimer{
        public MyCountDownTimer(long durings,long interval){
            super(durings,interval);
        }

        @Override
        public void onTick(long millisUntilFinished) {
            leftTime=millisUntilFinished;
            textView.setText(formatDuring(millisUntilFinished));
            Log.e("CrazyMO", "onTick"+String.valueOf(millisUntilFinished / 1000));
        }

        @Override
        public void onFinish() {
            Log.e("CrazyMO", "onFinish");
        }
    }

    public static String formatDuring(long mss) {
        long days = mss / (1000 * 60 * 60 * 24);
        long hours = (mss % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60);
        long minutes = (mss % (1000 * 60 * 60)) / (1000 * 60);
        long seconds = (mss % (1000 * 60)) / 1000;
        return days + " days " + hours + " hours " + minutes + " minutes "
                + seconds + " seconds ";
    }

    /**
     *
     * @param begin 时间段的开始
     * @param end   时间段的结束
     * @return  输入的两个Date类型数据之间的时间间格用* days * hours * minutes * seconds的格式展示
     */
    public static String formatDuring(Date begin, Date end) {
        return formatDuring(end.getTime() - begin.getTime());
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.e("CrazyMO", "onPause");
        countDownTimer.cancel();
        countDownTimer=null;
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.e("CrazyMO", "onPause"+leftTime);
        if(leftTime>1000) {
            countDownTimer = new MyCountDownTimer(leftTime, 1000).start();
        }
    }
}

运行结果

  • 当设置的总持续时间刚好是间隔时间的整数倍的时候,onTick按照间隔时间被调用直到持续时间结束,最后调用onFinish
    这里写图片描述
  • 当设置的总持续时间小于是间隔时间的,onTick将不会被触发,直接回调onFinish
    这里写图片描述
  • 当设置的总持续时间不是间隔时间的整数倍时,onTick按照间隔时间被调用直到持续时间结束,最后调用onFinish(设置持续时间6.5s,间隔1s)
    这里写图片描述
  • 在持续时间周期内手动cancel时,不会触发onFinish(设置持续时间12s,间隔时间1s 在6秒的时候手动cancel)
    这里写图片描述

二、定时和延时

android实现定时器的方式也有很多种:Handler类的postDelyed方法Handler+Timer+TimerTaskHandler+Thread,其实这三种方式核心就是Handler的通信。

1、Handler+Timer+TimerTask

这种方式本质就是在TimerTask 中发送Message,Handler负责接收并处理消息完成UI更新,最后由Timer负责启动计时。

public class CountdownActivity Activity extends Activity {
    TextView tvShow;
    private int i = 0;
    private int TIME = 1000;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        tvShow = (TextView) findViewById(R.id.tv_show);
        timer.schedule(task, 1000, 1000); // 1s后执行task,经过1s再次执行
    }

    Handler handler = new Handler() {
        public void handleMessage(Message msg) {
            if (msg.what == 1) {
                tvShow.setText(Integer.toString(i++));//更新UI
            }
            super.handleMessage(msg);
        };
    };
    Timer timer = new Timer();
    TimerTask task = new TimerTask() {

        @Override
        public void run() {
            // 需要做的事:发送消息
            Message message = new Message();
            message.what = 1;
            handler.sendMessage(message);
        }
    };
} 

2、Handler类的postDelyed方法

这种方法也很简单,本质就是利用Handler的postDelay方法不断触发回调,所以只需要构造postDelay的所需的参数即可

public class CountdownActivity extends Activity {
    TextView tvShow;
    private int i = 0;
    private final int TIME = 1000L;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        tvShow = (TextView) findViewById(R.id.tv_show);
        handler.postDelayed(runnable, TIME); //启动计时器每隔1s执行
        handler.removeCallbacks(runnable); 停止计时
    }

    Handler handler = new Handler();
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            try {
                handler.postDelayed(this, TIME);//每1秒执行一次runnable.
                tvShow.setText(Integer.toString(i++));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    };
}

3、Handler+Thread

这种方式不仅仅可以用于模拟计时,因为本质就是利用Handler实现线程间的通信,对于这种方式记得在倒计时完毕之后处理下子线程,别让线程一直在后台跑。

public class CountdownActivity extends Activity {
    TextView tvShow;
    private int i = 0;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        tvShow = (TextView) findViewById(R.id.tv_show);
        new Thread(new ThreadShow()).start();
    }

    // 主线程的handler接收并处理消息
    Handler handler = new Handler() {
        public void handleMessage(Message msg) {
            if (msg.what == 1) {
                tvShow.setText(Integer.toString(i++));//完成UI更新
                System.out.println("receive....");
            }
        }

        ;
    };

    // 在线程获得Handler对象并发送消息至主线程
    class ThreadShow implements Runnable {
        public  boolean isNeedRun=true;
        @Override
        public void run() {
            while (!Thread.currentThread().isInterrupted()&&isNeedRun) {
                try {
                    Thread.sleep(1000);
                    Message msg = new Message();
                    msg.what = 1;
                    handler.sendMessage(msg);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CrazyMo_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值