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     @Override31     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             @Override65             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                 else71                 {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     @Override102     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     <TextView17         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     <TextView25         android:id="@+id/preset"26         android:layout_width="fill_parent"27         android:layout_height="wrap_content"28         android:textColor="#000000"/>29     30     <EditText31         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     <Button38         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     <application10         android:icon="@drawable/ic_launcher"11         android:label="@string/app_name" >12         <activity13             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()    {        @Override        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。

        //创建计划任务        TimerTask task=new TimerTask()        {            @Override            public 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 }


更多相关文章

  1. Android(安卓)弹无虚发之第四弹:你应该掌握的Notification(Notific
  2. MonoDroid学习笔记(十二)—— 您有一条新短信息,请注意查收。状态栏
  3. Dump Window
  4. android 唤醒屏幕并解锁
  5. 运用IntentService类下载文件
  6. 自定义app锁屏页
  7. Android悬浮贴边按钮实现(含动画效果)
  8. android 8.0 兼容问题
  9. 屏幕亮屏、熄屏监听代码

随机推荐

  1. 【Android】调用系统应用常用uri & inten
  2. Androd学习笔记——Android中Touch事件的
  3. 【转】How to port native (C/C++) libra
  4. 《Android 获取当前app的版本号和版本名
  5. Android(安卓)Studio运行Hello World程序
  6. android 中给图片加圆角效果
  7. Android API 中文 (112) ―― ThumbnailU
  8. Android Binder机制(三) ServiceManager
  9. Android屏幕截图实现 (adbd部分)
  10. Ubuntu10.04 LTS 下编译Android