您的位置:首页 > 移动开发 > Android开发

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

2017-03-20 18:06 465 查看

引言

突然发现自己在博客中分了好多模块,每一个模块都还没能完整的总结完毕,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();
}
}
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息