Android 倒计时功能,完美解决系统时间更改后,倒计时不准问题。
1、Android倒计时大家一下子就会想到使用:timer.schedule();
我们查看schedule实现的源码:sched(task, System.currentTimeMillis()+delay, 0);
System.currentTimeMillis()这个玩意就是使用系统时间来做的,假如我们更改了系统时间,那倒计时就会出现问题!不信大家可以试试哈。。。。
2、如何解决这个问题呢?当然Android系统还提供了一个时间:开机时间 SystemClock.elapsedRealtime() 这个时间是开机时就记录的,和系统时间就没毛关系啦,更改系统时间也不会把开机时间更改的。
3、所以我们想要实现倒计时不被系统时间更改影响的话就可以使用到开机时间了。当然Android api也封装了使用开机时间的倒计时:CountDownTimer。
new CountDownTimer(timeMiao, 1000) {
@Override
public void onTick(long millisUntilFinished) {
}
@Override
public void onFinish() {
}
}.start();
好啦不废话直接上代码:
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.os.CountDownTimer;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
/**
*
* 倒计时控件
*/
public class TimeDownView extends LinearLayout {
private Context mContext;
private static final String TIME = "mm:ss";
private static final String MILLION = "S";
private String time = "00:00:00";
private String million = "0";
private CountDownTimer downTimer;
private DateFormat df, df2;
private TextView mText, mText2;
private int txtColor, txtBg, txtSize;
private int txtMillionColor, txtMillionBg, txtMillionSize;
private boolean millionShow = false;
private boolean isTimeDownOver = false;
private long millisSeconds = 0;
public TimeDownView(Context context) {
super(context);
initView(context, null);
}
public TimeDownView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initView(context, attrs);
}
public TimeDownView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context, attrs);
}
private void initView(Context context, AttributeSet attrs) {
mContext = context;
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TimeView);
millionShow = ta.getBoolean(R.styleable.TimeView_million_show, false);
txtColor = ta.getInt(R.styleable.TimeView_txt_color, Color.RED);
txtBg = ta.getInt(R.styleable.TimeView_txt_bg, Color.WHITE);
txtSize = ta.getInt(R.styleable.TimeView_txt_size, 13);
mText = new TextView(mContext);
mText.setTextColor(txtColor);
mText.setTextSize(txtSize);
mText.setBackgroundColor(txtBg);
mText.setText(time);
addView(mText);
df = createDateFormat(TIME);
if (millionShow) {
txtMillionColor = ta.getInt(R.styleable.TimeView_txt_million_color, Color.RED);
txtMillionBg = ta.getInt(R.styleable.TimeView_txt_million_bg, Color.WHITE);
txtMillionSize = ta.getInt(R.styleable.TimeView_txt_million_size, 13);
df2 = createDateFormat(MILLION);
mText2 = new TextView(mContext);
mText2.setTextColor(txtMillionColor);
mText2.setTextSize(txtMillionSize);
mText2.setBackgroundColor(txtMillionBg);
mText2.setText(million);
mText2.setPadding(5, 0, 5, 0);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT);
params.leftMargin = 10;
mText2.setLayoutParams(params);
addView(mText2);
}
}
public void startTime(long timeMillionMiao) {
if (timeMillionMiao < 1000) {
isTimeDownOver = true;
invalidate(0);
return;
}
if (downTimer != null) {
downTimer.onFinish();
downTimer.cancel();
}
downTimer = new CountDownTimer(timeMillionMiao, millionShow ? 100 : 1000) {
@Override
public void onTick(long millisUntilFinished) {
isTimeDownOver = false;
invalidate(millisUntilFinished);
}
@Override
public void onFinish() {
isTimeDownOver = true;
invalidate(0);
}
}.start();
}
public void invalidate(long millisSeconds) {
this.millisSeconds = millisSeconds;
mText.setText(formatTime(millisSeconds));
if (millionShow) {
Date date = new Date(millisSeconds);
mText2.setText(df2.format(date));
}
}
private DateFormat createDateFormat(String pattern) {
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
TimeZone gmt = TimeZone.getTimeZone("GMT");//关键所在
sdf.setTimeZone(gmt);
sdf.setLenient(true);
return sdf;
}
/**
* 毫秒转化时分秒
*/
public static String formatTime(long ms) {
int ss = 1000;
int mi = ss * 60;
int hh = mi * 60;
int dd = hh * 24;
long day = ms / dd;
long hour = (ms - day * dd) / hh;
long minute = (ms - day * dd - hour * hh) / mi;
long second = (ms - day * dd - hour * hh - minute * mi) / ss;
long milliSecond = ms - day * dd - hour * hh - minute * mi - second * ss;
hour = day * 24 + hour;
String strDay = day < 10 ? "0" + day : "" + day; //天
String strHour = hour < 10 ? "0" + hour : "" + hour;//小时
String strMinute = minute < 10 ? "0" + minute : "" + minute;//分钟
String strSecond = second < 10 ? "0" + second : "" + second;//秒
String strMilliSecond = milliSecond < 10 ? "0" + milliSecond : "" + milliSecond;//毫秒
strMilliSecond = milliSecond < 100 ? "0" + strMilliSecond : "" + strMilliSecond;
return strHour + ":" + strMinute + ":" + strSecond;
}
public boolean isTimeDownOver() {
return isTimeDownOver;
}
public long getMillisSeconds() {
return millisSeconds;
}
}
以上代码,我是把倒计时做成一个控件使用的,哈哈方便些。。。。有不足之处欢迎大家吐槽哈。。。。。。
最近用RxJava2也实现倒计时功能,很清爽:https://blog.youkuaiyun.com/Jocerly/article/details/84836104