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

来源:互联网 发布:黄巢吃人 知乎 编辑:程序博客网 时间:2024/06/06 02:39

引言

突然发现自己在博客中分了好多模块,每一个模块都还没能完整的总结完毕,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();                }            }        }    }}
0 0