赞
踩
转载请标明出处:
http://blog.csdn.net/mr_lawen/article/details/53381484
在我们的安卓项目中有时会有倒计时的需求,官方为我们提供了CountDownTimer这个类。下面就说说它的使用和原理。
使用方式
CountDownTimer是一个抽象类,我们需要定义一个它的实现类MyCountDownTimer(也可以直接在MainActivity中采用匿名类的方式)。
public class MyCountDownTimer extends CountDownTimer{
private onCountDownListener listener;
//第一个参数为倒计时总时长,第二个参数为倒计间隔
public MyCountDownTimer(long millisInFuture, long countDownInterval, onCountDownListener listener) {
super(millisInFuture, countDownInterval);
this.listener = listener;
}
@Override
public void onTick(long millisUntilFinished) {
//参数单位为毫秒,转化为秒
long time = millisUntilFinished / 1000;
//回调onTickShow()方法,传入倒计时剩余时间
listener.onTickShow(time);
}
@Override
public void onFinish() {
//倒计时完成,回调onFinishShow()方法
listener.onFinishShow();
}
public interface onCountDownListener {
void onTickShow(long left_time);
void onFinishShow();
}
}
再来看MainActivity
public class MainActivity extends AppCompatActivity {
private TextView tv_time_left;
private TextView tv_1;
private TextView tv_2;
private MyCountDownTimer mMyCountDownTimer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv_time_left = (TextView) findViewById(R.id.tv_time_left);
tv_1 = (TextView) findViewById(R.id.tv_1);
tv_2 = (TextView) findViewById(R.id.tv_2);
//实例化一个MyCountDownTimer对象,传入倒计总时长为10s,间隔为1s
//实例化一个onCountDownListener对象传入,重写两个方法,更新UI。
mMyCountDownTimer = new MyCountDownTimer(10000, 1000, new MyCountDownTimer.onCountDownListener({
@Override
public void onTickShow(long left_time) {
tv_time_left.setText(left_time+"");
}
@Override
public void onFinishShow() {
tv_time_left.setText("砰,炸弹爆炸了!");
tv_1.setText("");
tv_2.setText("");
}
});
//start方法开启倒计时
mMyCountDownTimer.start();
}
}
对应布局如下
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
tools:context="com.example.qn.countdowntimerdemo.MainActivity">
<TextView
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="总倒计时长10s,倒计间隔为1s" />
<LinearLayout
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tv_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="炸弹将在"/>
<TextView
android:id="@+id/tv_time_left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FF0000"
android:text="60"/>
<TextView
android:id="@+id/tv_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="s后爆炸,请迅速撤离!"/>
</LinearLayout>
</LinearLayout>
可以看到,CountDownTimer使用起来并不难,主要是重写它的两个方法onTick()和onFinish()。用起来不难的话,我们就应该看看它的原理。
原理解释
看源码
public abstract class CountDownTimer {
private final long mMillisInFuture; //倒计时总时长
private final long mCountdownInterval;//倒计时间隔
private long mStopTimeInFuture;//倒计时结束时间
private boolean mCancelled = false;
//传入倒计时总时长和间隔
public CountDownTimer(long millisInFuture, long countDownInterval) {
mMillisInFuture = millisInFuture;
mCountdownInterval = countDownInterval;
}
//取消倒计时
public synchronized final void cancel() {
mCancelled = true;
mHandler.removeMessages(MSG);
}
//start方法开始倒计时
public synchronized final CountDownTimer start() {
mCancelled = false;
if (mMillisInFuture <= 0) {
onFinish();
return this;
}
//倒计时停止时间 = 当前机器时间 + 倒计时总时长
mStopTimeInFuture = SystemClock.elapsedRealtime() + mMillisInFuture;
//发送一个消息开始倒计时
mHandler.sendMessage(mHandler.obtainMessage(MSG));
return this;
}
//该方法就是我们在MyCountDownTimer里重写的方法,每一个倒计时间隔调用一次,下面的代码//中就可以看到
public abstract void onTick(long millisUntilFinished);
//倒计时结束,也是我们需要重写的方法
public abstract void onFinish();
private static final int MSG = 1;
//可以看到这里用Handler进行发送消息和处理消息
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
synchronized (CountDownTimer.this) {
if (mCancelled) {
return;
}
//剩余时间 = 倒计时结束时间 – 当前机器时间
final long millisLeft = mStopTimeInFuture - SystemClock.elapsedRealtime();
//如果剩余时间<=0,结束倒计时
if (millisLeft <= 0) {
onFinish();
} else if (millisLeft < mCountdownInterval) {
//剩余时间不足一个倒计时间隔,那么就发送一个延时大小为剩余时间的消息
sendMessageDelayed(obtainMessage(MSG), millisLeft);
} else {
//否则
//记录下调用onTick()方法前的机器时间
long lastTickStart = SystemClock.elapsedRealtime();
//这里就是上面说的每个一个倒计时间隔就调用一个onTick()方法,传入剩余时//间
onTick(millisLeft);
//由于onTick()方法的执行耗费了一定的时间,所以延时消息的延时时间现在不//能是一个倒计时间隔了。
//它等于倒计时间隔 – onTick()方法执行时间
//即delay = mCountdownInterval – (当前机器时间 - 方法执行前的机器时间)
//即delay = mCountdownInterval-( SystemClock.elapsedRealtime()-lastTickStart)
//也就等于下面的式子。
long delay = lastTickStart + mCountdownInterval - SystemClock.elapsedRealtime();
//这里是一个特殊情况,防止delay是一个负值,即onTick花费时间超过了
//一个倒计时间隔
while (delay < 0) delay += mCountdownInterval;
//发出延时时间为delay的消息。
sendMessageDelayed(obtainMessage(MSG), delay);
}
}
}
};
}
总结
CountDownTimer利用传进来的倒计时间隔,发送延时消息,在消息处理时,每次间隔都调用一次onTick(),而我们早onTick()里做一些更新UI的操作,这就形成了倒计时的现象。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。