去年8月份用timer计时的一段程序在画UI的时候没有正常绘制,最近在查原因,发现踩了timer的坑,处理完后特此来记录一下。
Android中经常会在一段时间内重复去做一些事情,如开机向导的时候系统网络连接的比较慢,会耗时一会,这时候开机向导需要多次去检查系统网络有没有连接上,没有连接上才需要去在执行下面的流程。
类似于这种的重复多次执行一段程序的方法有很多种,总结一下目前可以实现的几种方法:
1、可以通过for循环加sleep来实现;
//10s内检测是否满足某种条件
for (int i = 0; i < 10; i++) {
if (满足条件) {
break;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
2、可以通过timer来实现
Timer timer = new Timer();
TimerTask task;
final int PERIOD = 1000;
int count = 0;
task = new TimerTask() {
@Override
public void run() {
// TODO Auto-generated method stub
if(满足条件)
{
recycleTimer();
}
count++;
if(count >= 10)
{
recycleTimer();
}
}
private void recycleTimer()
{
count = 0;
if(task != null)
task.cancel();
task = null;
if(timer != null)
timer.cancel();
timer = null;
}
};
timer.schedule(task, 0, PERIOD);
最近遇到一个比较奇怪的问题,android刚开机的时候在开机向导处,用timer计时去执行一个程序的时候,发现timer走到一半会假死,就不再执行后面的操作了,也是随机性的出来。
在网上查资料时,大家很多都推荐不要使用timer,timer有很多奇怪的问题,而且对系统时间比较敏感,尤其是系统时间发生变化的时候,timer就执行异常了。
我抓取了自己使用timer异常的情况,发现在开机的时候系统时间发生了跳变,由于系统在开机向导处系统会联网,时间会发生跳变,系统时间由默认的8:00多时间跳变到了14:00多时间,很大可能会导致timer发生问题,这个是timer设计上了缺陷。
最后打了一个补丁,启动timer计时执行的时候,同步执行了一个handler,如果handler检测到timer内部10s内还没有set退出循环的变量,就强行set此变量来退出循环。
现在大都推荐使用线程池ScheduledThreadPoolExecutor来替代timer。
3、使用计时器来实现
LoadAccountPageCountDownTimer loadingTimer;
class LoadAccountPageCountDownTimer extends CountDownTimer {
public LoadAccountPageCountDownTimer(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
// TODO Auto-generated constructor stub
}
@Override
public void onFinish() {
// TODO Auto-generated method stub
Debugger.d(LogModel.GUIDE, "LoadAccountPageCountDownTimer on finish");
if(满足什么条件) {
return ;
}
//计时结束后,仍未满足条件执行后续流程
......
}
//每秒检查一次
@Override
public void onTick(long arg0) {
// TODO Auto-generated method stub
if (满足什么条件) {
stopLoadAccountPageTimer();
}
}
}
private void startLoadAccountPageTimer() {
if (loadingTimer != null) {
loadingTimer.cancel();
}
if (loadingTimer == null) {
loadingTimer = new LoadAccountPageCountDownTimer(10000, 1000);//10s中每隔1s检查一次
}
loadingTimer.start();
}
private void stopLoadAccountPageTimer() {
if (loadingTimer != null) {
loadingTimer.cancel();
loadingTimer = null;
}
}
4、 通过handler来实现
如果涉及到UI的更新,可以用Handler来实现,每隔1s发送一次MSG来检查条件是否满足,如果满足条件,就不再发送MSG进行重复检查;或者超过10s就不再进行检查。
public abstract class BaseActivity extends Activity {
private static DelayCheckHandler delayCheckHandler = null;
private static final int MSG_CHECK_IS_OK = 0x00;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
delayCheckHandler = new DelayCheckHandler(this);
delayCheckHandler.sendEmptyMessageDelayed(MSG_CHECK_IS_OK,1000);
}
int count = 0;
private static class DelayCheckHandler extends Handler {
WeakReference<BaseActivity> refActivity;
private DelayCheckHandler(BaseActivity activity) {
super(Looper.myLooper());
this.refActivity = new WeakReference<BaseActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
if (refActivity == null || refActivity.get() == null) {
return;
}
switch (msg.what) {
case MSG_CHECK_IS_OK:
refActivity.get().checkIsOk();
break;
default:
break;
}
super.handleMessage(msg);
}
}
private void checkIsOk() {
if (满足条件) {
//TODO:更新UI
return;
}
if (count >= 10) {
return;
}
count++;
delayCheckHandler.sendEmptyMessageDelayed(MSG_CHECK_IS_OK,1000);
}
}
5、通过线程池来进行周期性执行某个任务
private ScheduledThreadPoolExecutor executorService;
private IsNewModuleInsertRunnable runnable = null;
private count = 0;
//创建线程池,里面只有1个线程
executorService = new ScheduledThreadPoolExecutor(1, new ThreadFactory() {
private AtomicInteger atoInteger = new AtomicInteger(0);
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setName("check-loop-thread "+ atoInteger.getAndIncrement());
return t;
}
});
runnable = new IsNewModuleInsertRunnable();
//首次延时1s,后面每隔1s执行一次runable线程
executorService.scheduleWithFixedDelay(runnable, 1, 1, TimeUnit.SECONDS);
//注意线程的执行方法最好不要耗时超过线程执行的周期,否则会出现执行周期不是很准确问题
private class IsNewModuleInsertRunnable implements Runnable {
@Override
public void run() {
try {
if (满足条件) {
//TODO:
stopThread();
return;
}
if (count >= 10) {
stopThread();
return;
}
count++;
} catch (Exception e) {
e.printStackTrace();
L.d("exception !!!, " + e.getMessage());
}
}
}
//停止正在执行的任务
private void stopThread() {
executorService.shutdownNow();
}
微信公众号:一点微时光
欢迎关注我,一起学习,一起进步!