idea来源

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

1、能记录屏幕使用时间

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

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

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; 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 ; 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")); // 启动服务 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); 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); // 最终显示 57 // 显示已保存的设置 58 int limit=sp.getInt("limit", 24*60 ); 59 preset.setText(" 当前设定的预警分钟数为"+ Integer.toString(limit)); 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 }); 82 } 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; 18 /** 19 * 创建一个服务,该服务主要用来接收广播和创建定时器 20 * @author 林培东 21 */ 22 public class LocalService extends Service 23 { 24 private static final int NOTIFY_ID=1234; // 通知的唯一标识符 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(); 35 if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) 36 { 37 // 保存屏幕启动时的毫秒数 38 editor.putLong("lasttime", new Date().getTime()); 39 editor.commit(); 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 } 65 }; 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); 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(); 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); // 测试用 98 super .onCreate(); 99 } 101 @Override 102 public IBinder onBind(Intent arg0) 103 { 104 return null ; 105 } 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" >
 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" />
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" />
24     <TextView
25         android:id="@+id/preset"
26         android:layout_width="fill_parent"
27         android:layout_height="wrap_content"
28         android:textColor="#000000"/>
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" />
37     <Button
38         android:id="@+id/submit"
39         android:layout_width="fill_parent"
40         android:layout_height="wrap_content"
41         android:text="确定提交" />
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" >
 7     <uses-sdk android:minSdkVersion="4" />
 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" />
18                 <category android:name="android.intent.category.LAUNCHER" />
19             </intent-filter>
20         </activity>
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>
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()来处理这些数据,主要功能都在里面实现:

public 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。

// 每天凌晨自动更新数据 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); // 测试用
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这个广播,因为它一分钟就发送一次,是个可靠的广播,只要判断下时间点,就可以决定是否更新了。

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

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

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

最后,修改后的代码:

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; 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 ; 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(); 35 if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) 36 { 37 // 保存屏幕启动时的毫秒数 38 editor.putLong("lasttime", new Date().getTime()); 39 editor.commit(); 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(); 72 // 取消通知栏通知 73 final NotificationManager manager= (NotificationManager)getSystemService(NOTIFICATION_SERVICE); 74 manager.cancel(NOTIFY_ID); 75 } 76 } 78 } 80 }; 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); 92 super .onCreate(); 93 } 95 @Override 96 public IBinder onBind(Intent arg0) 97 { 98 return null ; 99 } 101 }
Android Screen Monitor:实时 监控 安卓 屏幕 的利器 android -screen-monitor Android Screen Monitor项目地址:https://gitcode.com/gh_mirrors/an/ android -screen-monitor 项目介绍 Android Screen Monitor (ASM) 是一款强大的工具,旨在实时 监控 安卓设备或模拟器的...
Android screen monitor: Android 屏幕 监控 1.下载asm.jar http://adakoda.github.io/ android -screen-monitor/ 最新版本Version3.0.0 放在/home/xx/tools/ android -sdk-linux/platform-tools目录下 2.运行脚本asm ---------------
2.只保留时钟,可设定指针和数字、夜间模式; 3.启用 时间 改多长 时间 无操作进入 保,可设定1、5、10、15、30分钟; 4.如果休眠 时间 设定小于 时间 ,则优先进入休眠,如果休眠 时间 设定大于 时间 ,则先进入 保,达到休眠 时间 后再进入休眠 修改后的效果 分析与实现: 1.由于 Android 原生系统默认进入 保的条件是充电或插入基座时,但到达休眠时才进入...
博客源址: Android 屏幕 待机 时间 获取 和设置 应用 场景:紧接的是Adnroid 屏幕 度调节——设置到指定的值与恢复到原来的值这一篇的 应用 场景,条形码图片扫码的问题。 屏幕 待机 时间 太短,正在扫着突然 屏幕 黑了,肯定不行。因此,这篇是解决这个问题的。 屏幕 待机 时间 的读取,不需要任何权限。 [java] view plain copy
Android Profiler分为三大模块: cpu、内存 、网络。基本的 使用 在上一篇文章有讲到。这里详细说一下。cpu分析器CPU ProfilerCPU分析器可帮助您实时检查 应用 程序的CPU 使用 情况和线程活动,并记录方法跟踪,以便您可以优化和调试 应用 程序的代码。要打开CPU Profiler,请按照下列步骤操作: 点击 View > Tool Windows > Android Profile
今年早些时候as升级到了3.0版本,自己前两天升级了,发现之前我们熟悉的 Android Monitor 不在了,取而代之的是 Android Profiler,就参照官方文档过了一遍。 1: Android Profiler的是 使用 流程: 1.点击工具栏的图标即可打开 在 Android Profiler窗口的顶部,如图所示,选择设备 和你想要配置的app进程 当我们连接一个设备后,打开And...
我之前只看了一篇消息队列的文章,感觉比你这篇写得好,里面包括RabbitMQ、Kafka、RocketMQ和ActiveMQ这4种队列的对比和选型,关键是每种队列的原理都描述的非常清楚,希望可以一起学习交流~~ 《消息队列:从选型到原理,一文带你全部掌握》:https://mp.weixin.qq.com/s/Gb9k_LxQhOPDcMGxDJ9Jvw 如何使用thread dump?你将如何分析Thread dump? 加油当当: 太真实了,天下文章一大抄,你抄我来我抄他,很恶心 UML的9种图例解析 further_: 图片怎么显示不出来呀