这几天有个APP需要在刷了NFC后一段时间内保持一个状态不改变,比如10min内一直保持一个状态,然后再到了10min时做一个判断,更新其最新状态。当时一想到这个场景,立马就想到了使用android中定时器Timer来实现这个功能,起初也没多想,直到测试的时候才发现这个Timer在运行时有很多问题。比如,Timer在手机锁屏的情况下就会停止运行,当开屏的时候才会继续倒计时,还有就是Timer在锁屏的情况下可能会被回收。
在网上查阅帖子后,找到了一篇测试Timer的文章,写的很好。
原文地址是:http://blog.csdn.net/lzqjfly/article/details/8021551
============================================================================
目标: 希望采用Timer来计时,要求在服务中运行,每10分钟记录一次数据。但是采用timer来做了以后,发现统计的次数没有达到预期的目标。甚至没有运行,以下是在测试情况
1.为了能够看到测试效果,将循环时间设置为2秒
本打算用服务做测试,但为了方便就用activity做测试
- /**
- ?*?对计时器的测试
- ?*/
- import?java.util.Timer;
- import?java.util.TimerTask;
- import?android.app.Activity;
- import?android.os.Bundle;
- import?android.os.Handler;
- import?android.os.Message;
- import?android.widget.TextView;
- public?class?TimerActivity?extends?Activity?{
- ????private?TextView?txtCount;
- ????private?int?count;
- ????//处理界面
- ????private??Handler?handler?=?new?Handler(){
- ????????public?void?handleMessage(android.os.Message?msg)?{
- ????????????if(msg.arg1?==?1){
- ????????????????txtCount.setText(String.valueOf(count));
- ????????????}
- ????????};
- ????};
- ????@Override
- ????protected?void?onCreate(Bundle?savedInstanceState)?{
- ????????//?TODO?Auto-generated?method?stub
- ????????super.onCreate(savedInstanceState);
- ????????setContentView(R.layout.activity_main);
- ????????this.txtCount?=?(TextView)findViewById(R.id.count);
- ????????new?Timer().schedule(countTask,?10,?2000);??//延迟10毫秒,每2秒钟执行一次?????
- ????}
- ????//任务
- ????TimerTask?countTask?=?new?TimerTask()?{
- ????????@Override
- ????????public?void?run()?{
- ????????????//?TODO?Auto-generated?method?stub
- ????????????count?++;
- ????????????Message?msg?=?new?Message();
- ????????????msg.arg1?=?1;
- ????????????handler.sendMessage(msg);
- ????????}
- ????};
- }
结果:
1.将手机与电脑连接测试,改程序正常,能够一直运行。并且按下电源键后仍然能够正常运行,统计的次数也正常
2.手机与电脑断开连接后,然后重新运行改程序,该程序能正常运行。然后按下电源键,手机处于待机状态,过一段时间后在看屏幕上的次数,发现次数没有动,不知道为啥???
3.手机与电脑断开连接后,运行程序,然后按home键,在手机没有处于待机的状态下,统计的次数发生变化,能够正常运行。但是如果手机处于待机状态后,程序不在运行。
问题: 手机待机后会让大部分程序不在运行(除电话,短信等)。难道这是系统的保护机制???
2.采用线程的Sleep处理;
- package?com.test.timertest;
- /**
- ?*?对计时器的测试
- ?*/
- import?java.util.Timer;
- import?java.util.TimerTask;
- import?android.app.Activity;
- import?android.os.Bundle;
- import?android.os.Handler;
- import?android.os.Message;
- import?android.widget.TextView;
- public?class?TimerActivity?extends?Activity?{
- ????private?TextView?txtCount;
- ????private?int?count;
- ????//处理界面
- ????private??Handler?handler?=?new?Handler(){
- ????????public?void?handleMessage(android.os.Message?msg)?{
- ????????????if(msg.arg1?==?1){
- ????????????????txtCount.setText(String.valueOf(count));
- ????????????}
- ????????};
- ????};
- ????@Override
- ????protected?void?onCreate(Bundle?savedInstanceState)?{
- ????????//?TODO?Auto-generated?method?stub
- ????????super.onCreate(savedInstanceState);
- ????????setContentView(R.layout.activity_main);
- ????????this.txtCount?=?(TextView)findViewById(R.id.count);
- //??????new?Timer().schedule(countTask,?10,?2000);??//延迟10毫秒,每2秒钟执行一次?????
- ????????new?CountThread().start();
- ????}
- ????class?CountThread?extends?Thread{
- ????????@Override
- ????????public?void?run()?{
- ????????????while(true){
- ????????????????count?++;
- ????????????????Message?msg?=?new?Message();
- ????????????????msg.arg1?=?1;
- ????????????????handler.sendMessage(msg);
- ????????????????try?{
- ????????????????????Thread.sleep(2000);
- ????????????????}?catch?(InterruptedException?e)?{
- ????????????????????//?TODO?Auto-generated?catch?block
- ????????????????????e.printStackTrace();
- ????????????????}
- ????????????}
- ????????}
- ????}
- //??//任务
- //??TimerTask?countTask?=?new?TimerTask()?{
- //??????
- //??????@Override
- //??????public?void?run()?{
- //??????????//?TODO?Auto-generated?method?stub
- //??????????count?++;
- //??????????Message?msg?=?new?Message();
- //??????????msg.arg1?=?1;
- //??????????handler.sendMessage(msg);
- //??????}
- //??};
- }
采用Sleep的处理结果和上面1中的一样,怀疑是不是activity和thread有区别,于是采用线程来处理,并将结果保存到xml中
服务如下:
- package?com.test.timertest;
- import?java.util.Timer;
- import?java.util.TimerTask;
- import?android.app.Service;
- import?android.content.Context;
- import?android.content.Intent;
- import?android.content.SharedPreferences;
- import?android.content.SharedPreferences.Editor;
- import?android.os.IBinder;
- public?class?CountService?extends?Service?{
- ????@Override
- ????public?IBinder?onBind(Intent?intent)?{
- ????????//?TODO?Auto-generated?method?stub
- ????????return?null;
- ????}
- ????@Override
- ????public?void?onCreate()?{
- ????????//?TODO?Auto-generated?method?stub
- ????????super.onCreate();
- ????????new?Timer().schedule(countTask,?10,?2000);???//2秒钟
- ????}
- ????//?任务
- ????TimerTask?countTask?=?new?TimerTask()?{
- ????????@Override
- ????????public?void?run()?{
- ????????????saveAppCount();
- ????????}
- ????};
- ????//?保存数据
- ????private?void?saveAppCount()?{
- ????????int?count?=?getAppCount()?+?1;
- ????????SharedPreferences?sf?=?getSharedPreferences(“appcount”,
- ????????????????Context.MODE_PRIVATE);
- ????????Editor?editor?=?sf.edit();
- ????????editor.putInt(“count”,?count);
- ????????editor.commit();
- ????}
- ????//?获取数据
- ????public?int?getAppCount()?{
- ????????SharedPreferences?spf?=?getSharedPreferences(“appcount”,
- ????????????????Context.MODE_PRIVATE);
- ????????return?spf.getInt(“count”,?0);
- ????}
- }
显示数据的activity
- package?com.test.timertest;
- /**
- ?*?对计时器的测试
- ?*/
- import?android.app.Activity;
- import?android.content.Context;
- import?android.content.Intent;
- import?android.content.SharedPreferences;
- import?android.os.Bundle;
- import?android.widget.TextView;
- public?class?TimerActivity?extends?Activity?{
- ????private?TextView?txtCount;
- ????@Override
- ????protected?void?onCreate(Bundle?savedInstanceState)?{
- ????????//?TODO?Auto-generated?method?stub
- ????????super.onCreate(savedInstanceState);
- ????????setContentView(R.layout.activity_main);
- ????????this.txtCount?=?(TextView)findViewById(R.id.count);
- ????????SharedPreferences?spf?=?getSharedPreferences(“appcount”,
- ????????????????Context.MODE_PRIVATE);
- ????????int?count?=??spf.getInt(“count”,?0);
- ????????txtCount.setText(String.valueOf(count));
- ????????Intent?intent?=?new?Intent(this,CountService.class);
- ????????startService(intent);
- ????}
- }
测试结果::
1.手机和电脑连接,手机处于调试模式,不管是按下电源键让手机处于待机状态还是按下home键,服务都能够正常的统计数据
2.手机与电脑断开连接,不管是手机自动处于待机状态还是主动按下电源键让手机处于待机状态,服务里面的线程都没有正常的记录数据。 求解 ???
最终结合网上资料采用AlarmManager 控制计时操作,能够保证系统在sleep的时候发出广播,达到统计的目的
- package?com.test.timertest;
- /**
- ?*?对计时器的测试
- ?*/
- import?java.util.Timer;
- import?android.app.Activity;
- import?android.app.AlarmManager;
- import?android.app.PendingIntent;
- import?android.content.Context;
- import?android.content.Intent;
- import?android.content.SharedPreferences;
- import?android.os.Bundle;
- import?android.os.SystemClock;
- import?android.widget.TextView;
- public?class?TimerActivity?extends?Activity?{
- ????private?TextView?txtCount;
- ????public?final?String?ACTION?=?“com.test.timertest.alarmreciver”;
- ????@Override
- ????protected?void?onCreate(Bundle?savedInstanceState)?{
- ????????//?TODO?Auto-generated?method?stub
- ????????super.onCreate(savedInstanceState);
- ????????setContentView(R.layout.activity_main);
- ????????this.txtCount?=?(TextView)findViewById(R.id.count);
- ????????SharedPreferences?spf?=?getSharedPreferences(“appcount”,
- ????????????????Context.MODE_PRIVATE);
- ????????int?count?=??spf.getInt(“count”,?0);
- ????????txtCount.setText(String.valueOf(count));
- //??????Intent?intent?=?new?Intent(this,CountService.class);
- //??????startService(intent);
- ????????//闹钟全局变量
- ????????AlarmManager?am?=?(AlarmManager)getSystemService(ALARM_SERVICE);
- ????????Intent?intent?=?new?Intent(ACTION);
- ????????PendingIntent?sender?=?PendingIntent.getBroadcast(this,?0,?intent,?0);
- ????????long?firsttime?=?SystemClock.elapsedRealtime();
- ????????firsttime??+=?2*1000;
- ????????am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,firsttime,?2*1000,sender);??//AlarmManager.ELAPSED_REALTIME_WAKEUP?这里要用这个类型的tiype才能保证系统在sleep的时候也能发广播,不懂的可以去看文档的介绍
- ????}
- }
接受广播的类
- package?com.test.timertest;
- import?android.content.BroadcastReceiver;
- import?android.content.Context;
- import?android.content.Intent;
- import?android.content.SharedPreferences;
- import?android.content.SharedPreferences.Editor;
- public?class?AlarmReciver?extends?BroadcastReceiver?{
- ????@Override
- ????public?void?onReceive(Context?context,?Intent?intent)?{
- ????????//?TODO?Auto-generated?method?stub
- ????????saveAppCount(context);
- ????}
- ????//?保存数据
- ????private?void?saveAppCount(Context?context)?{
- ????????int?count?=?getAppCount(context)?+?1;
- ????????SharedPreferences?sf?=?context.getSharedPreferences(“appcount”,
- ????????????????Context.MODE_PRIVATE);
- ????????Editor?editor?=?sf.edit();
- ????????editor.putInt(“count”,?count);
- ????????editor.commit();
- ????}
- ????//?获取数据
- ????public?int?getAppCount(Context?context)?{
- ????????SharedPreferences?spf?=?context.getSharedPreferences(“appcount”,
- ????????????????Context.MODE_PRIVATE);
- ????????return?spf.getInt(“count”,?0);
- ????}
- }