利用Timer实现倒计时
@BindView(R.id.send) Button send;//发送验证码
private int time = 60;//倒计时
private Timer timer;
private Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case 1:
send.setText(time + "S");
break;
case 2:
send.setEnabled(true);
send.setText("重新发送");
break;
}
}
};
@OnClick({R.id.send, R.id.next})
public void onClickIv(View v) {
switch (v.getId()) {
case R.id.send:
send.setEnabled(false);
getVerificationCode();
break;
}
}
//定时器
private void setTimer() {
timer = new Timer();
TimerTask task = new TimerTask() {
@Override
public void run() {
time--;
if (time > 0) handler.sendEmptyMessage(1);
else {
handler.sendEmptyMessage(2);
destoryTimer();
}
}
};
timer.schedule(task, 0, 1000);
}
private void destoryTimer() {
if (timer != null) {
timer.cancel();
timer = null;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
destoryTimer();
}
当然也可以不用Handler而用其他更精简的API,比如:
TimerTask task = new TimerTask() {
@Override
public void run() {
runOnUiThread(new Runnable() {
@Override
public void run() {
time--;
if (time > 0) send.setText(time + "S");
else {
send.setEnabled(true);
send.setText("重新发送");
destoryTimer();
}
}
});
}
};
利用Handler实现倒计时
handler.sendMessageDelayed(handler.obtainMessage(1), 1000);
final Handler handler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
time--;
if (time > 0) {
send.setText(time + "S");
handler.sendMessageDelayed(handler.obtainMessage(1), 1000);
} else {
send.setEnabled(true);
send.setText("重新发送");
}
}
}
};
类似的实现方式
Handler handler = new Handler();
handler.postDelayed(runnable, 1000);
Runnable runnable = new Runnable() {
@Override
public void run() {
time--;
if (time > 0) {
send.setText(time + "S");
handler.postDelayed(this, 1000);
} else {
send.setEnabled(true);
send.setText("重新发送");
}
}
};
利用CountDownTimer实现
CountDownTimer timer = new CountDownTimer(60000, 1000) {
@Override
public void onTick(long millisUntilFinished) {
send.setText(time + "S");
}
@Override
public void onFinish() {
send.setEnabled(true);
send.setText("重新发送");
}
};
GitHub上星星最多的倒计时控件
CountdownView:Android倒计时控件,使用Canvas绘制,支持多种样式
compile 'com.github.iwgang:countdownview:2.1.3'
XML
<cn.iwgang.countdownview.CountdownView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
基本使用
CountdownView mCountdownView = (CountdownView)findViewById(R.id.countdownView);
mCountdownView.start(995550000); // 毫秒
// 或者自己编写倒计时逻辑,然后调用updateShow来更新UI
for (int time=0; time<1000; time++) {
mCountdownView.updateShow(time);
}
动态显示设置, 支持所有xml中的配置项来使用java代码设置
mCountdownView.dynamicShow(DynamicConfig dynamicConfig)
倒计时结束后回调
mCountdownView.setOnCountdownEndListener(OnCountdownEndListener);
指定间隔时间回调
mCountdownView.setOnCountdownIntervalListener(long, OnCountdownIntervalListener);
RecyclerView中倒计时方案1【最简单】
这种方案在数据量特别小(即List的size()特别小),且刷新item及计算倒计时耗费的时间特别短时适用,否则,将会产生巨大的时间延迟。
1、更改数据源(即重新设置倒计时剩余时间)
//定时器,用于刷新GridView的数据源
private void setQryTimer() {
cancelQryTimer();
qryTimer = new Timer();
qryTimer.schedule(new TimerTask() {
@Override
public void run() {
runOnUiThread(new Runnable() {
public void run() {
if (fixRpList != null && fixRpList.size() > 0) {
for (FixRpBean item : fixRpList) {
if (item.diff_time >= 0) item.diff_time = item.diff_time - 1000L;
}
if (fixRpDialog != null) fixRpDialog.upDate(fixRpList);
}
}
});
}
}, 0, 1000);
}
2、刷新item(建议使用RecyclerView的局部刷新功能)
public void upDate(List<FixRpBean> redPacketList) {
list.clear();
list.addAll(redPacketList);
mRecyclerView.getAdapter().notifyDataSetChanged();//建议使用RecyclerView的局部刷新功能
}
RecyclerView中倒计时方案2【推荐】
核心思想为:利用System.currentTimeMillis()帮我们计算倒计时。
并且:在onViewAttachedToWindow时重新开始倒计时,在onViewDetachedFromWindow时关闭倒计时。
/**
* 复用 本地的计时器 —— System.currentTimeMillis(), 不必自行计时
*/
public class RecyclerViewActivity extends Activity {
private List<ItemInfo> mDataList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recyclerview);
initData();
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.rv);
recyclerView.setAdapter(new MyAdapter(this, mDataList));
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
recyclerView.setItemAnimator(new DefaultItemAnimator());
}
private void initData() {
mDataList = new ArrayList<>();
for (int i = 1; i < 20; i++) {
mDataList.add(new ItemInfo(i * 20 * 1000));
}
// 校对倒计时
long curTime = System.currentTimeMillis();
for (ItemInfo itemInfo : mDataList) {
itemInfo.endTime = curTime + itemInfo.countdown;
}
}
static class MyAdapter extends RecyclerView.Adapter<MyViewHolder> {
private Context mContext;
private List<ItemInfo> mDatas;
public MyAdapter(Context context, List<ItemInfo> datas) {
this.mContext = context;
this.mDatas = datas;
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new MyViewHolder(LayoutInflater.from(mContext).inflate(R.layout.list_item, parent, false));
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
holder.bindData(mDatas.get(holder.getAdapterPosition()));
}
@Override
public int getItemCount() {
return mDatas.size();
}
//**************************************************关键代码****************************************
@Override
public void onViewAttachedToWindow(MyViewHolder holder) {
super.onViewAttachedToWindow(holder);//父类中为空代码
holder.refreshTime(mDatas.get(holder.getAdapterPosition()).endTime - System.currentTimeMillis());
}
@Override
public void onViewDetachedFromWindow(MyViewHolder holder) {
super.onViewDetachedFromWindow(holder);
holder.countdownView.stop();
}
//**************************************************关键代码****************************************
}
static class MyViewHolder extends RecyclerView.ViewHolder {
public CountdownView countdownView;
public MyViewHolder(View itemView) {
super(itemView);
countdownView = (CountdownView) itemView.findViewById(R.id.countdownView);
}
public void bindData(ItemInfo itemInfo) {
refreshTime(itemInfo.endTime - System.currentTimeMillis());
}
public void refreshTime(long leftTime) {
if (leftTime > 0) {
countdownView.start(leftTime);
} else {
countdownView.stop();//停止计时器,mCustomCountDownTimer.stop();
countdownView.allShowZero();//所有计时清零,即mCountdown.setTimes(0, 0, 0, 0, 0);
}
}
}
static class ItemInfo {
public long countdown;
/*
根据服务器返回的countdown换算成手机对应的开奖时间 (毫秒)
[正常情况最好由服务器返回countdown字段,然后客户端再校对成该手机对应的时间,不然误差很大]
*/
public long endTime;
public ItemInfo(long countdown) {
this.countdown = countdown;
}
}
}
RecyclerView中倒计时方案3【最麻烦】
这种方案为:自己维护倒计时,再调用countdownView.updateShow来刷新显示
并且:在onResume时开启倒计时,在onPause及onDestroy时关闭倒计时。
个人极其不推荐这种方案,既麻烦又低效。
/*
自己维护倒计时任何,再调用countdownView.updateShow来刷新显示
*/
public class RecyclerViewActivity2 extends AppCompatActivity {
private MyAdapter mMyAdapter;
private List<ItemInfo> mDataList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recyclerview);
initData();
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.rv);
mMyAdapter = new RecyclerViewActivity2.MyAdapter(this, mDataList);
recyclerView.setAdapter(mMyAdapter);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
recyclerView.setItemAnimator(new DefaultItemAnimator());
}
private void initData() {
mDataList = new ArrayList<>();
for (int i = 1; i < 20; i++) {
mDataList.add(new ItemInfo(1000 + i, "RecyclerView_测试标题_" + i, i * 20 * 1000));
}
// 校对倒计时
long curTime = System.currentTimeMillis();
for (ItemInfo itemInfo : mDataList) {
itemInfo.setEndTime(curTime + itemInfo.getCountdown());
}
}
@Override
protected void onResume() {
super.onResume();
if (null != mMyAdapter)
mMyAdapter.startRefreshTime();}
@Override
protected void onPause() {
super.onPause();
if (null != mMyAdapter)
mMyAdapter.cancelRefreshTime();}
@Override
public void onDestroy() {
super.onDestroy();
if (null != mMyAdapter)
mMyAdapter.cancelRefreshTime();}
static class MyAdapter extends RecyclerView.Adapter<MyViewHolder> {
private Context mContext;
private List<ItemInfo> mDatas;
private final SparseArray<MyViewHolder> mCountdownVHList;
private Handler mHandler = new Handler();
private Timer mTimer;
private boolean isCancel = true;
public MyAdapter(Context context, List<ItemInfo> datas) {
this.mContext = context;
this.mDatas = datas;
mCountdownVHList = new SparseArray<>();
startRefreshTime();
}
public void startRefreshTime() {
if (!isCancel) return;
if (null != mTimer) mTimer.cancel();
isCancel = false;
mTimer = new Timer();
mTimer.schedule(new TimerTask() {
@Override
public void run() {
mHandler.post(mRefreshTimeRunnable);
}
}, 0, 10);
}
public void cancelRefreshTime() {
isCancel = true;
if (null != mTimer) {
mTimer.cancel();
}
mHandler.removeCallbacks(mRefreshTimeRunnable);
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new MyViewHolder(LayoutInflater.from(mContext).inflate(R.layout.list_item, parent, false));
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
ItemInfo curItemInfo = mDatas.get(position);
holder.bindData(curItemInfo);
// 处理倒计时
if (curItemInfo.getCountdown() > 0) {
synchronized (mCountdownVHList) {
mCountdownVHList.put(curItemInfo.getId(), holder);
}
}
}
@Override
public int getItemCount() {
return mDatas.size();
}
@Override
public void onViewRecycled(MyViewHolder holder) {
super.onViewRecycled(holder);
ItemInfo curAnnounceGoodsInfo = holder.getBean();
if (null != curAnnounceGoodsInfo && curAnnounceGoodsInfo.getCountdown() > 0) {
mCountdownVHList.remove(curAnnounceGoodsInfo.getId());
}
}
private Runnable mRefreshTimeRunnable = new Runnable() {
@Override
public void run() {
if (mCountdownVHList.size() == 0) return;
synchronized (mCountdownVHList) {
long currentTime = System.currentTimeMillis();
int key;
for (int i = 0; i < mCountdownVHList.size(); i++) {
key = mCountdownVHList.keyAt(i);
MyViewHolder curMyViewHolder = mCountdownVHList.get(key);
if (currentTime >= curMyViewHolder.getBean().getEndTime()) {
curMyViewHolder.getBean().setCountdown(0);// 倒计时结束
mCountdownVHList.remove(key);
notifyDataSetChanged();
} else {
curMyViewHolder.refreshTime(currentTime);
}
}
}
}
};
}
static class MyViewHolder extends RecyclerView.ViewHolder {
private TextView mTvTitle;
private CountdownView mCvCountdownView;
private ItemInfo mItemInfo;
public MyViewHolder(View itemView) {
super(itemView);
mTvTitle = (TextView) itemView.findViewById(R.id.tv_title);
mCvCountdownView = (CountdownView) itemView.findViewById(R.id.cv_countdownView);
}
public void bindData(ItemInfo itemInfo) {
mItemInfo = itemInfo;
if (itemInfo.getCountdown() > 0) {
refreshTime(System.currentTimeMillis());
} else {
mCvCountdownView.allShowZero();
}
mTvTitle.setText(itemInfo.getTitle());
}
public void refreshTime(long curTimeMillis) {
if (null == mItemInfo || mItemInfo.getCountdown() <= 0) return;
mCvCountdownView.updateShow(mItemInfo.getEndTime() - curTimeMillis);
}
public ItemInfo getBean() {
return mItemInfo;
}
}
static class ItemInfo {
private int id;
private String title;
private long countdown;
/*
根据服务器返回的countdown换算成手机对应的开奖时间 (毫秒)
[正常情况最好由服务器返回countdown字段,然后客户端再校对成该手机对应的时间,不然误差很大]
*/
private long endTime;
public ItemInfo(int id, String title, long countdown) {
this.id = id;
this.title = title;
this.countdown = countdown;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public long getCountdown() {
return countdown;
}
public void setCountdown(long countdown) {
this.countdown = countdown;
}
public long getEndTime() {
return endTime;
}
public void setEndTime(long endTime) {
this.endTime = endTime;
}
}
}
2017-6-12