Android小应用——监控屏幕使用时间

idea来源

这个idea是蔡小亦童鞋提出来的。她说看到一条报道说有人看手机看太久眼睛怎么怎么了,所以想弄个应用来监控屏幕使用时间。答应帮她做已经答应很久了,刚好这周没什么事了,于是就开始做。从开始找资料到写代码到美工到调试完成,只花了1天时间,不错不错~因为我觉得这个做得很粗糙别人不可能会怎么用,所以我就针对蔡小亦童鞋定制了流氓兔形象,哦哈哈是不是该感谢我~

预期目标

1、能记录屏幕使用时间

2、每天凌晨清空数据,重新记录

3、用户可以自定义警戒线,当使用时间超过警戒线则在通知栏提醒。

主要代码

 1 package com.legend;
 2
 3 import java.text.SimpleDateFormat;
 4 import java.util.Date;
 5
 6 import android.app.Activity;
 7 import android.content.Context;
 8 import android.content.Intent;
 9 import android.content.SharedPreferences;
10 import android.os.Bundle;
11 import android.view.View;
12 import android.view.View.OnClickListener;
13 import android.widget.Button;
14 import android.widget.EditText;
15 import android.widget.TextView;
16 import android.widget.Toast;
17
18 /**
19  * 目前先实现最小功能,只提取出总的屏幕亮的时间
20  * 通过广播来接收屏幕是否启动这个事件
21  * @author 林培东
22  */
23 public class MainActivity extends Activity
24 {
25     public TextView summary=null;
26     public TextView preset=null;
27     public EditText set=null;
28     public Button submit=null;
29
30     @Override
31     public void onCreate(Bundle savedInstanceState)
32     {
33         super.onCreate(savedInstanceState);
34         setContentView(R.layout.main);
35         startService(new Intent("com.legend.SERVICE_DEMO"));//启动服务
36
37         summary=(TextView)findViewById(R.id.summary);
38         preset=(TextView)findViewById(R.id.preset);
39         set=(EditText)findViewById(R.id.set);
40         submit=(Button)findViewById(R.id.submit);
41
42         //显示已使用屏幕时间
43           SharedPreferences sp=getSharedPreferences("actm", Context.MODE_PRIVATE);
44           int sum=(int)sp.getLong("sum", 0L)/1000;
45           int hour=sum/3600;
46           int minute=(sum-hour*3600)/60;
47           int second=sum%60;
48           //格式化输出日期
49           Date tmp=new Date();
50           tmp.setHours(hour);
51           tmp.setMinutes(minute);
52           tmp.setSeconds(second);
53           SimpleDateFormat sdf=new SimpleDateFormat("HH:mm:ss");
54           String result=sdf.format(tmp);
55           summary.setText(result);//最终显示
56
57           //显示已保存的设置
58           int limit=sp.getInt("limit", 24*60);
59           preset.setText(" 当前设定的预警分钟数为"+Integer.toString(limit));
60
61           //点击确定后重新设置
62           submit.setOnClickListener(new OnClickListener()
63           {
64             @Override
65             public void onClick(View v)
66             {
67                 String tmp=set.getText().toString();
68                 if(tmp.equals(""))
69                     Toast.makeText(MainActivity.this, "输入不能为空!", Toast.LENGTH_SHORT).show();
70                 else
71                 {
72                     SharedPreferences sp=getSharedPreferences("actm", Context.MODE_PRIVATE);
73                     SharedPreferences.Editor editor=sp.edit();
74                     editor.putInt("limit", Integer.parseInt(tmp));
75                     editor.commit();
76                     Toast.makeText(MainActivity.this, "已设定!", Toast.LENGTH_SHORT).show();
77                     preset.setText(" 当前设定的预警分钟数为"+Integer.parseInt(tmp));
78                 }
79             }
80           });
81
82     }
83
84 }

  1 package com.legend;
  2
  3 import java.util.Date;
  4 import java.util.Timer;
  5 import java.util.TimerTask;
  6
  7 import android.app.Notification;
  8 import android.app.NotificationManager;
  9 import android.app.PendingIntent;
 10 import android.app.Service;
 11 import android.content.BroadcastReceiver;
 12 import android.content.Context;
 13 import android.content.Intent;
 14 import android.content.IntentFilter;
 15 import android.content.SharedPreferences;
 16 import android.os.IBinder;
 17
 18 /**
 19  * 创建一个服务,该服务主要用来接收广播和创建定时器
 20  * @author 林培东
 21  */
 22 public class LocalService extends Service
 23 {
 24     private static final int NOTIFY_ID=1234;//通知的唯一标识符
 25
 26     //主要功能,广播接收器
 27     private final BroadcastReceiver receiver=new BroadcastReceiver()
 28     {
 29         @Override
 30         public void onReceive(Context context, Intent intent)
 31         {
 32             SharedPreferences sp=getSharedPreferences("actm", Context.MODE_PRIVATE);
 33             SharedPreferences.Editor editor=sp.edit();
 34
 35             if(intent.getAction().equals(Intent.ACTION_SCREEN_ON))
 36             {
 37                 //保存屏幕启动时的毫秒数
 38                 editor.putLong("lasttime", new Date().getTime());
 39                 editor.commit();
 40
 41                 //根据需要看是否需要在通知栏提醒
 42                 int sum=(int)sp.getLong("sum", 0L)/1000;
 43                 int limit=sp.getInt("limit", 1440)*60;
 44                 if(limit<=sum)
 45                 {
 46                     final NotificationManager manager=(NotificationManager)getSystemService(NOTIFICATION_SERVICE);//获取通知管理器
 47                     Notification notification=new Notification(R.drawable.ic_launcher,"警告",System.currentTimeMillis());//通知的时机
 48                     notification.flags = Notification.FLAG_AUTO_CANCEL;//点击一次通知就自动消失
 49                     PendingIntent pIntent=PendingIntent.getActivity(context,0,new Intent(context,MainActivity.class),0);//跳转到主界面
 50                     notification.setLatestEventInfo(context,"警告","本日使用屏幕已超过预设,如需取消该警告请重新设置!!!",pIntent);//通知栏显示内容
 51                     manager.notify(NOTIFY_ID, notification);//执行
 52                 }
 53             }
 54             else if(intent.getAction().equals(Intent.ACTION_SCREEN_OFF))
 55             {
 56                 //保存屏幕总工作时间
 57                 long lasttime=sp.getLong("lasttime", new Date().getTime());
 58                 long sum=sp.getLong("sum", 0L);
 59                 sum+=new Date().getTime()-lasttime;
 60                 editor.putLong("sum", sum);
 61                 editor.commit();
 62             }
 63         }
 64
 65     };
 66
 67     @Override
 68     public void onCreate()
 69     {
 70         //添加过滤器并注册
 71         final IntentFilter filter=new IntentFilter();
 72         filter.addAction(Intent.ACTION_SCREEN_ON);
 73         filter.addAction(Intent.ACTION_SCREEN_OFF);
 74         registerReceiver(receiver, filter);
 75
 76         //创建计划任务
 77         TimerTask task=new TimerTask()
 78         {
 79             @Override
 80             public void run()
 81             {
 82                 //每天凌晨自动更新数据
 83                 SharedPreferences sp=getSharedPreferences("actm", Context.MODE_PRIVATE);
 84                 SharedPreferences.Editor editor=sp.edit();
 85                 editor.putLong("sum", 0L);
 86                 editor.commit();
 87
 88                 //取消通知栏通知
 89                 final NotificationManager manager=(NotificationManager)getSystemService(NOTIFICATION_SERVICE);
 90                 manager.cancel(NOTIFY_ID);
 91             }
 92         };
 93         Timer timer=new Timer(true);
 94         int hour=new Date().getHours();
 95         timer.schedule(task,(24-hour)*3600*1000, 24*3600*1000);
 96         //timer.schedule(task,180*1000, 180*1000);//测试用
 97
 98         super.onCreate();
 99     }
100
101     @Override
102     public IBinder onBind(Intent arg0)
103     {
104         return null;
105     }
106
107 }

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:layout_width="fill_parent"
 4     android:layout_height="fill_parent"
 5     android:background="@drawable/background"
 6     android:orientation="vertical" >
 7
 8     <TextView
 9         android:layout_width="fill_parent"
10         android:layout_height="wrap_content"
11         android:textSize="25dp"
12         android:text="今天屏幕总共使用"
13         android:textColor="#000000"
14         android:gravity="center" />
15
16     <TextView
17         android:id="@+id/summary"
18         android:layout_width="fill_parent"
19         android:layout_height="wrap_content"
20         android:textSize="50dp"
21         android:textColor="#000000"
22         android:gravity="center" />
23
24     <TextView
25         android:id="@+id/preset"
26         android:layout_width="fill_parent"
27         android:layout_height="wrap_content"
28         android:textColor="#000000"/>
29
30     <EditText
31         android:id="@+id/set"
32         android:layout_width="fill_parent"
33         android:layout_height="wrap_content"
34         android:hint="请输入预警提醒分钟数,如80"
35         android:inputType="number" />
36
37     <Button
38         android:id="@+id/submit"
39         android:layout_width="fill_parent"
40         android:layout_height="wrap_content"
41         android:text="确定提交" />
42
43 </LinearLayout>

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
 3     package="com.legend"
 4     android:versionCode="1"
 5     android:versionName="1.0" >
 6
 7     <uses-sdk android:minSdkVersion="4" />
 8
 9     <application
10         android:icon="@drawable/ic_launcher"
11         android:label="@string/app_name" >
12         <activity
13             android:name=".MainActivity"
14             android:label="@string/app_name" >
15             <intent-filter>
16                 <action android:name="android.intent.action.MAIN" />
17
18                 <category android:name="android.intent.category.LAUNCHER" />
19             </intent-filter>
20         </activity>
21
22         <service android:name=".LocalService">
23             <intent-filter>
24                 <action android:name="com.legend.SERVICE_DEMO" />
25                 <category android:name="android.intent.category.default" />
26             </intent-filter>
27         </service>
28     </application>
29
30 </manifest>

项目分析

我遇到的第一个问题是:如何监控?

经过查资料,我发现当屏幕启用或者锁屏时,系统会分别发送ACTION_SCREEN_ON和ACTION_SCREEN_OFF这两个广播。我们只需要在接收这两个广播时记录时间就可以了。

注意:为了时程序退出后也能运行,必须使用Service。

注意:这两个广播是受保护的,只能在代码中注册。

下面是在Service中注册:

        //添加过滤器并注册final IntentFilter filter=new IntentFilter();filter.addAction(Intent.ACTION_SCREEN_ON);filter.addAction(Intent.ACTION_SCREEN_OFF);registerReceiver(receiver, filter);

在接收器receiver里,定义了onReceive()来处理这些数据,主要功能都在里面实现:

    //主要功能,广播接收器private final BroadcastReceiver receiver=new BroadcastReceiver(){@Overridepublic void onReceive(Context context, Intent intent){SharedPreferences sp=getSharedPreferences("actm", Context.MODE_PRIVATE);SharedPreferences.Editor editor=sp.edit();if(intent.getAction().equals(Intent.ACTION_SCREEN_ON)){//保存屏幕启动时的毫秒数                editor.putLong("lasttime", new Date().getTime());editor.commit();//根据需要看是否需要在通知栏提醒int sum=(int)sp.getLong("sum", 0L)/1000;int limit=sp.getInt("limit", 1440)*60;if(limit<=sum){final NotificationManager manager=(NotificationManager)getSystemService(NOTIFICATION_SERVICE);//获取通知管理器Notification notification=new Notification(R.drawable.ic_launcher,"警告",System.currentTimeMillis());//通知的时机notification.flags = Notification.FLAG_AUTO_CANCEL;//点击一次通知就自动消失PendingIntent pIntent=PendingIntent.getActivity(context,0,new Intent(context,MainActivity.class),0);//跳转到主界面notification.setLatestEventInfo(context,"警告","本日使用屏幕已超过预设,如需取消该警告请重新设置!!!",pIntent);//通知栏显示内容manager.notify(NOTIFY_ID, notification);//执行
                }}else if(intent.getAction().equals(Intent.ACTION_SCREEN_OFF)){//保存屏幕总工作时间long lasttime=sp.getLong("lasttime", new Date().getTime());long sum=sp.getLong("sum", 0L);sum+=new Date().getTime()-lasttime;editor.putLong("sum", sum);editor.commit();}}};

另一个问题是如何在每天凌晨自动把sum置零。一开始我查资料找到了ACTION_DATE_CHANGED这个广播,但测试时发现不可靠,网上也说了这个广播各种不可靠。

这里做了说明:http://4develop.in/csdn/Android/20111230_12_f516e79c-d732-4963-961b-4e0bd2f35437/1

于是,只能忍痛使用定时器来制定计划任务了:Timer和TimerTask。

        //创建计划任务TimerTask task=new TimerTask(){@Overridepublic void run(){//每天凌晨自动更新数据SharedPreferences sp=getSharedPreferences("actm", Context.MODE_PRIVATE);SharedPreferences.Editor editor=sp.edit();editor.putLong("sum", 0L);editor.commit();//取消通知栏通知final NotificationManager manager=(NotificationManager)getSystemService(NOTIFICATION_SERVICE);manager.cancel(NOTIFY_ID);}           };Timer timer=new Timer(true);int hour=new Date().getHours();timer.schedule(task,(24-hour)*3600*1000, 24*3600*1000);//timer.schedule(task,180*1000, 180*1000);//测试用

再有就是学习了如何使用通知栏来推送消息。

可以参考:http://fanwei51880.blog.163.com/blog/static/32406740201052754236166/

final NotificationManager manager=(NotificationManager)getSystemService(NOTIFICATION_SERVICE);//获取通知管理器
Notification notification=new Notification(R.drawable.ic_launcher,"警告",System.currentTimeMillis());//通知的时机
notification.flags = Notification.FLAG_AUTO_CANCEL;//点击一次通知就自动消失
PendingIntent pIntent=PendingIntent.getActivity(context,0,new Intent(context,MainActivity.class),0);//跳转到主界面
notification.setLatestEventInfo(context,"警告","本日使用屏幕已超过预设,如需取消该警告请重新设置!!!",pIntent);//通知栏显示内容
manager.notify(NOTIFY_ID, notification);//执行

最后,上一下截图:

--------------------------------------后记-------------------------------------------

本来以为很简单的,没想到修改了两次才能正常运作:不知道为什么系统老是把资源回收了,结果凌晨都无法自动清空数据。

第一次修改,是取消守护线程了。之前对这个不了解,查了下资料,原来所谓的守护线程,就是当线程要守护的资源不存在时,这个线程也就退出了。所以我想这就是原因了吧,修改,还信心满满地以为不用测试了。

结果零点就不行了,严重被打击==!

无奈之下,只好用最原始的方法了:监听Intent.ACTION_TIME_TICK这个广播,因为它一分钟就发送一次,是个可靠的广播,只要判断下时间点,就可以决定是否更新了。

其实这个方法我很早就想到了,只是我觉得这样每分钟都要做一次判断,太麻烦和太耗资源了。这算是程序员的通病吧。

所以,通过这个小软件,我也有了一点体会:功能第一,性能第二。因为用户最后用的是你的软件的功能,而性能是很难看出来的;只要影响不大的话。

所以,真的不应该在这个问题上钻牛角尖,一定要最优化。

最后,修改后的代码:

  1 package com.legend;
  2
  3 import java.util.Calendar;
  4 import java.util.Date;
  5
  6 import android.app.Notification;
  7 import android.app.NotificationManager;
  8 import android.app.PendingIntent;
  9 import android.app.Service;
 10 import android.content.BroadcastReceiver;
 11 import android.content.Context;
 12 import android.content.Intent;
 13 import android.content.IntentFilter;
 14 import android.content.SharedPreferences;
 15 import android.os.IBinder;
 16
 17 /**
 18  * 创建一个服务,该服务主要用来接收广播和创建定时器
 19  * @author 林培东
 20  */
 21 public class LocalService extends Service
 22 {
 23     private static final int NOTIFY_ID=1234;//通知的唯一标识符
 24     private Calendar cal=null;
 25
 26     //主要功能,广播接收器
 27     private final BroadcastReceiver receiver=new BroadcastReceiver()
 28     {
 29         @Override
 30         public void onReceive(Context context, Intent intent)
 31         {
 32             SharedPreferences sp=getSharedPreferences("actm", Context.MODE_PRIVATE);
 33             SharedPreferences.Editor editor=sp.edit();
 34
 35             if(intent.getAction().equals(Intent.ACTION_SCREEN_ON))
 36             {
 37                 //保存屏幕启动时的毫秒数
 38                 editor.putLong("lasttime", new Date().getTime());
 39                 editor.commit();
 40
 41                 //根据需要看是否需要在通知栏提醒
 42                 int sum=(int)sp.getLong("sum", 0L)/1000;
 43                 int limit=sp.getInt("limit", 1440)*60;
 44                 if(limit<=sum)
 45                 {
 46                     final NotificationManager manager=(NotificationManager)getSystemService(NOTIFICATION_SERVICE);//获取通知管理器
 47                     Notification notification=new Notification(R.drawable.ic_launcher,"警告",System.currentTimeMillis());//通知的时机
 48                     notification.flags = Notification.FLAG_AUTO_CANCEL;//点击一次通知就自动消失
 49                     PendingIntent pIntent=PendingIntent.getActivity(context,0,new Intent(context,MainActivity.class),0);//跳转到主界面
 50                     notification.setLatestEventInfo(context,"警告","本日使用屏幕已超过预设,如需取消该警告请重新设置!!!",pIntent);//通知栏显示内容
 51                     manager.notify(NOTIFY_ID, notification);//执行
 52                 }
 53             }
 54             else if(intent.getAction().equals(Intent.ACTION_SCREEN_OFF))
 55             {
 56                 //保存屏幕总工作时间
 57                 long lasttime=sp.getLong("lasttime", new Date().getTime());
 58                 long sum=sp.getLong("sum", 0L);
 59                 sum+=new Date().getTime()-lasttime;
 60                 editor.putLong("sum", sum);
 61                 editor.commit();
 62             }
 63             else if(intent.getAction().equals(Intent.ACTION_TIME_TICK))
 64             {
 65                 cal=Calendar.getInstance();
 66                 if(cal.get(Calendar.HOUR_OF_DAY)==0 && cal.get(Calendar.MINUTE)==0)
 67                 {
 68                     //每天凌晨自动更新数据
 69                     editor.putLong("sum", 0L);
 70                     editor.commit();
 71
 72                     //取消通知栏通知
 73                     final NotificationManager manager=(NotificationManager)getSystemService(NOTIFICATION_SERVICE);
 74                     manager.cancel(NOTIFY_ID);
 75                 }
 76             }
 77
 78         }
 79
 80     };
 81
 82     @Override
 83     public void onCreate()
 84     {
 85         //添加过滤器并注册
 86         final IntentFilter filter=new IntentFilter();
 87         filter.addAction(Intent.ACTION_SCREEN_ON);
 88         filter.addAction(Intent.ACTION_SCREEN_OFF);
 89         filter.addAction(Intent.ACTION_TIME_TICK);
 90         registerReceiver(receiver, filter);
 91
 92         super.onCreate();
 93     }
 94
 95     @Override
 96     public IBinder onBind(Intent arg0)
 97     {
 98         return null;
 99     }
100
101 }

Android小应用——监控屏幕使用时间相关推荐

  1. android p屏幕使用时间,MIUI迎来第414周更新,新增屏幕使用时间,小米6获Android P更新!...

    原标题:MIUI迎来第414周更新,新增屏幕使用时间,小米6获Android P更新! 今天,我们迎来了本月最后一次MIUI开发版的升级,官方也是在上午的时候如期推送MIUI第414周更新通知,系统版 ...

  2. 屏幕使用时间 android,你的屏幕使用时间是多少?

    图片发自简书App 最近发现苹果手机的设置里面多了一个屏幕使用时间,它可以统计你每天使用手机的时间.真是不看不知道,一看吓一跳.之前一直觉得自己玩手机的频率还不算太高,但是从屏幕使用时间显示的数据来看 ...

  3. 独立开发变现周刊(第81期):开发一个应用来减少屏幕使用时间,月收入2万美元...

    分享独立开发.产品变现相关内容,每周五发布. (合集:https://ezindie.com/weekly ) 目录 1.组件世界 WidgetStore:一个丰富.强大的嵌入式小组件库 2.Dist ...

  4. android屏幕适配的目的,Android 不同分辨率下屏幕适配的实战方案与经验总结

    Android 开发中,屏幕适配是一大考点,几乎每一场面试,都不会落下这个问题,这个问题说简单也简单,说难也难,当然对于有过真实的适配经验的人来说,这个根本不算什么问题,从坑里爬过的人,自然知道这其中 ...

  5. android手机可以设置屏幕锁定,安卓手机屏幕锁设置方法(九个点图案)

    这里以三星S5368手机屏幕锁为例 随着三星S5368手机系统功能愈来愈完善,性能愈来愈强劲,越来越多的三星S5368用户们都喜欢把一些重要的信息甚至隐私放在三星S5368手机里面,但是这就有可能会让 ...

  6. android10手机众筹,最小Android 10手机?屏幕仅3英寸的Jelly 2开始众筹

    原标题:最小Android 10手机?屏幕仅3英寸的Jelly 2开始众筹 DoNews 7月22日消息(记者 刘文轩)在那些已经逝去的智能手机中,Palm可以算是相当具有"考古" ...

  7. Android小知识10则(上)(2018.8重编版)

    Android小知识10则(下) 目录 前言 横竖屏锁定 不同分辨率的图标 将字符串写在资源文件中 为AlertDialog设置点击监听 ProgressDialog了解一下 最后 前言 Androi ...

  8. android系统如何自适应屏幕大小

    2019独角兽企业重金招聘Python工程师标准>>> 1.屏幕相关概念 1.1分辨率 是指屏幕上有横竖各有多少个像素 1.2屏幕尺寸 指的是手机实际的物理尺寸,比如常用的2.8英寸 ...

  9. android小游戏模版—重力感应

    好久没更新博客了,今天来谈谈android小游戏---重力感应,一般在游戏里运用的比較多,比方这类游戏有:神庙逃亡.极品飞车,平衡球.三围重力迷宫,重力赛车等. 首先什么是重力感应.重力感应是指如今手 ...

最新文章

  1. 团队项目博客---移山小分队---3
  2. 博士申请 | 佐治亚理工学院陈永昕教授招收机器学习理论方向博士生
  3. 面试官问:来实现一个Promise
  4. MSSQL-Scripter,一个新的生成T-SQL脚本的SQL Server命令行工具
  5. TrustBase团队完成subscript语言的Web3基金会Grant资助计划项目交付
  6. Python生成1000个随机字符的字符串,统计每个字符的出现次数(choices函数和Counter的使用)
  7. 深度学习中的数据增强方法
  8. java配环境变量_用于 Java 开发的配置工具 Simple Configuration Facade
  9. 使用librtmp接收数据时要注意的问题
  10. 数值计算软件有哪些?一款国产软件非常亮眼。
  11. [RPA之家]UiPath程序设计文档
  12. UE4_C++_自定义细节面板_Customizing detail panels
  13. Android照片墙应用实现,再多的图片也不怕崩溃
  14. 腾讯云服务器性能评测:8核 16G 18M 配置
  15. 增强 Jupyter Notebook 的功能,这里有四个妙招
  16. 原创图片可以进行版权登记吗?
  17. 告诫程序员们,大三/大四有必要去实习吗?
  18. 计算机主板和硬盘连接吗,我的计算机主板只有一个SATA2接口. 如何连接硬盘和光驱? -...
  19. 并联谐振电路工作原理详解,案例+计算公式,几分钟带你搞定
  20. deepin安装配置jdk环境变量

热门文章

  1. 达梦数据库中各种表的管理
  2. vue实现实例搜索和排序
  3. 智能设备主要有哪些特点
  4. Unity对象的简单平移与旋转
  5. PyTorch中的torch.clamp()实现矩阵裁剪
  6. 多目标优化拥挤距离计算
  7. [Linux Audio Driver] SM6350平台音频bring up ( 一 )
  8. 中国RFID行业市场前景规划与运营模式分析报告2022-2028年版
  9. ic启动器怎么导入模组_晶圆代工产能将紧缺至何时?联电/世界先进/中芯国际/联发科的大佬们怎么看?...
  10. 看世界杯效应下的中东市场,开发攻略来了