Android:每小时获取 UsageStats
Android: get UsageStats per hour
我用的是Android的UsageStats
特征,但是最小区间是DAILY INTERVAL
。
long time = System.currentTimeMillis();
List<UsageStats> appList = manager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - DAY_IN_MILLI_SECONDS, time);
我怎样才能以每小时的间隔获得 UsageStats
?
是的,Android 提供最低 INTERVAL_DAILY
。但为了获得最佳结果,您可以使用 INTERVAL_BEST
。 Android 正在为 queryUsageStats(int, long, long)
中的给定时间范围提供最佳间隔计时器。
编码愉快...
我认为这不可能,即使您在间隔中间请求数据,看起来数据存储在桶中并且最小桶是一天。
在 UsageStatsManager 文档中,它说:
A request for data in the middle of a time interval will include that interval.
此外,INTERVAL_BEST
不是真正的时间间隔,它只是选择给定时间范围内的可用时间间隔之一。在
UsageStatsManager.java源代码,它说:
/**
* The number of available intervals. Does not include {@link #INTERVAL_BEST}, since it
* is a pseudo interval (it actually selects a real interval).
* {@hide}
*/
public static final int INTERVAL_COUNT = 4;
所有功劳归于 this answer。我从那个那里学到了。
我们如何收集自定义时间范围内的应用程序使用数据(例如,每 1 小时)?
我们必须调用 queryEvents(long begin_time, long end_time)
method as it will provide us all data starting from begin_time
to end_time
. It give us each app data through foreground
and background
events instead of total spent time like queryUsageStats()
方法。所以,使用前台和后台事件时间戳,我们可以统计一个应用程序的启动次数,也可以找出每个应用程序的使用时长。
实现收集最后 1 小时的应用程序使用数据
首先,在AndroidManifest.xml
文件中添加以下行,同时请求用户获得使用权限。
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
在任何方法中添加以下行
long hour_in_mil = 1000*60*60; // In Milliseconds
long end_time = System.currentTimeMillis();
long start_time = end_time - hour_in_mil;
然后,调用方法getUsageStatistics()
getUsageStatistics(start_time, end_time);
getUsageStatistics 方法
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
void getUsageStatistics(long start_time, long end_time) {
UsageEvents.Event currentEvent;
// List<UsageEvents.Event> allEvents = new ArrayList<>();
HashMap<String, AppUsageInfo> map = new HashMap<>();
HashMap<String, List<UsageEvents.Event>> sameEvents = new HashMap<>();
UsageStatsManager mUsageStatsManager = (UsageStatsManager)
context.getSystemService(Context.USAGE_STATS_SERVICE);
if (mUsageStatsManager != null) {
// Get all apps data from starting time to end time
UsageEvents usageEvents = mUsageStatsManager.queryEvents(start_time, end_time);
// Put these data into the map
while (usageEvents.hasNextEvent()) {
currentEvent = new UsageEvents.Event();
usageEvents.getNextEvent(currentEvent);
if (currentEvent.getEventType() == UsageEvents.Event.ACTIVITY_RESUMED ||
currentEvent.getEventType() == UsageEvents.Event.ACTIVITY_PAUSED) {
// allEvents.add(currentEvent);
String key = currentEvent.getPackageName();
if (map.get(key) == null) {
map.put(key, new AppUsageInfo(key));
sameEvents.put(key,new ArrayList<UsageEvents.Event>());
}
sameEvents.get(key).add(currentEvent);
}
}
// Traverse through each app data which is grouped together and count launch, calculate duration
for (Map.Entry<String,List<UsageEvents.Event>> entry : sameEvents.entrySet()) {
int totalEvents = entry.getValue().size();
if (totalEvents > 1) {
for (int i = 0; i < totalEvents - 1; i++) {
UsageEvents.Event E0 = entry.getValue().get(i);
UsageEvents.Event E1 = entry.getValue().get(i + 1);
if (E1.getEventType() == 1 || E0.getEventType() == 1) {
map.get(E1.getPackageName()).launchCount++;
}
if (E0.getEventType() == 1 && E1.getEventType() == 2) {
long diff = E1.getTimeStamp() - E0.getTimeStamp();
map.get(E0.getPackageName()).timeInForeground += diff;
}
}
}
// If First eventtype is ACTIVITY_PAUSED then added the difference of start_time and Event occuring time because the application is already running.
if (entry.getValue().get(0).getEventType() == 2) {
long diff = entry.getValue().get(0).getTimeStamp() - start_time;
map.get(entry.getValue().get(0).getPackageName()).timeInForeground += diff;
}
// If Last eventtype is ACTIVITY_RESUMED then added the difference of end_time and Event occuring time because the application is still running .
if (entry.getValue().get(totalEvents - 1).getEventType() == 1) {
long diff = end_time - entry.getValue().get(totalEvents - 1).getTimeStamp();
map.get(entry.getValue().get(totalEvents - 1).getPackageName()).timeInForeground += diff;
}
}
smallInfoList = new ArrayList<>(map.values());
// Concatenating data to show in a text view. You may do according to your requirement
for (AppUsageInfo appUsageInfo : smallInfoList)
{
// Do according to your requirement
strMsg = strMsg.concat(appUsageInfo.packageName + " : " + appUsageInfo.launchCount + "\n\n");
}
TextView tvMsg = findViewById(R.id.MA_TvMsg);
tvMsg.setText(strMsg);
} else {
Toast.makeText(context, "Sorry...", Toast.LENGTH_SHORT).show();
}
}
AppUsageInfo.class
import android.graphics.drawable.Drawable;
class AppUsageInfo {
Drawable appIcon; // You may add get this usage data also, if you wish.
String appName, packageName;
long timeInForeground;
int launchCount;
AppUsageInfo(String pName) {
this.packageName=pName;
}
}
如何自定义这些代码以收集每 1 小时的数据?
如要获取每小时数据,请更改每小时数据的end_time
和start_time
值。例如:如果我尝试收集过去每小时的数据(对于过去 2 小时的数据)。 我会做以下事情。
long end_time = System.currentTimeMillis();
long start_time = end_time - (1000*60*60);
getUsageStatistics(start_time, end_time);
end_time = start_time;
start_time = start_time - hour_in_mil;
getUsageStatistics(start_time, end_time);
但是,您可以使用Handler
跳过重复写入start_time
和end_time
来更改这些变量的值。每次采集一小时数据,完成一个任务,自动改变变量值后,再次调用getUsageStatistics
方法
注意:也许,您将无法检索过去 7.5 天以上的数据,因为 events are only kept by the system for a few days。
Calendar cal = (Calendar) Calendar.getInstance().clone();
//I used this and it worked, only for 7 days and a half ago
if (daysAgo == 0) {
//Today - I only count from 00h00m00s today to present
end = cal.getTimeInMillis();
start = LocalDate.now().toDateTimeAtStartOfDay().toInstant().getMillis();
} else {
long todayStartOfDayTimeStamp = LocalDate.now().toDateTimeAtStartOfDay().toInstant().getMillis();
if (mDaysAgo == -6) {
//6 days ago, only get events in time -7 days to -7.5 days
cal.setTimeInMillis(System.currentTimeMillis());
cal.add(Calendar.DATE, daysAgo + 1);
end = cal .getTimeInMillis();
start = end - 43200000;
} else {
//get events from 00h00m00s to 23h59m59s
//Current calendar point to 0h0m today
cal.setTimeInMillis(todayStartOfDayTimeStamp);
cal.add(Calendar.DATE, daysAgo + 1);
end = calendar.getTimeInMillis();
cal.add(Calendar.DATE, -1);
start = calendar.getTimeInMillis();
}
}
我用的是Android的UsageStats
特征,但是最小区间是DAILY INTERVAL
。
long time = System.currentTimeMillis();
List<UsageStats> appList = manager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - DAY_IN_MILLI_SECONDS, time);
我怎样才能以每小时的间隔获得 UsageStats
?
是的,Android 提供最低 INTERVAL_DAILY
。但为了获得最佳结果,您可以使用 INTERVAL_BEST
。 Android 正在为 queryUsageStats(int, long, long)
中的给定时间范围提供最佳间隔计时器。
编码愉快...
我认为这不可能,即使您在间隔中间请求数据,看起来数据存储在桶中并且最小桶是一天。 在 UsageStatsManager 文档中,它说:
A request for data in the middle of a time interval will include that interval.
此外,INTERVAL_BEST
不是真正的时间间隔,它只是选择给定时间范围内的可用时间间隔之一。在
UsageStatsManager.java源代码,它说:
/**
* The number of available intervals. Does not include {@link #INTERVAL_BEST}, since it
* is a pseudo interval (it actually selects a real interval).
* {@hide}
*/
public static final int INTERVAL_COUNT = 4;
所有功劳归于 this answer。我从那个那里学到了。
我们如何收集自定义时间范围内的应用程序使用数据(例如,每 1 小时)?
我们必须调用 queryEvents(long begin_time, long end_time)
method as it will provide us all data starting from begin_time
to end_time
. It give us each app data through foreground
and background
events instead of total spent time like queryUsageStats()
方法。所以,使用前台和后台事件时间戳,我们可以统计一个应用程序的启动次数,也可以找出每个应用程序的使用时长。
实现收集最后 1 小时的应用程序使用数据
首先,在AndroidManifest.xml
文件中添加以下行,同时请求用户获得使用权限。
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
在任何方法中添加以下行
long hour_in_mil = 1000*60*60; // In Milliseconds
long end_time = System.currentTimeMillis();
long start_time = end_time - hour_in_mil;
然后,调用方法getUsageStatistics()
getUsageStatistics(start_time, end_time);
getUsageStatistics 方法
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
void getUsageStatistics(long start_time, long end_time) {
UsageEvents.Event currentEvent;
// List<UsageEvents.Event> allEvents = new ArrayList<>();
HashMap<String, AppUsageInfo> map = new HashMap<>();
HashMap<String, List<UsageEvents.Event>> sameEvents = new HashMap<>();
UsageStatsManager mUsageStatsManager = (UsageStatsManager)
context.getSystemService(Context.USAGE_STATS_SERVICE);
if (mUsageStatsManager != null) {
// Get all apps data from starting time to end time
UsageEvents usageEvents = mUsageStatsManager.queryEvents(start_time, end_time);
// Put these data into the map
while (usageEvents.hasNextEvent()) {
currentEvent = new UsageEvents.Event();
usageEvents.getNextEvent(currentEvent);
if (currentEvent.getEventType() == UsageEvents.Event.ACTIVITY_RESUMED ||
currentEvent.getEventType() == UsageEvents.Event.ACTIVITY_PAUSED) {
// allEvents.add(currentEvent);
String key = currentEvent.getPackageName();
if (map.get(key) == null) {
map.put(key, new AppUsageInfo(key));
sameEvents.put(key,new ArrayList<UsageEvents.Event>());
}
sameEvents.get(key).add(currentEvent);
}
}
// Traverse through each app data which is grouped together and count launch, calculate duration
for (Map.Entry<String,List<UsageEvents.Event>> entry : sameEvents.entrySet()) {
int totalEvents = entry.getValue().size();
if (totalEvents > 1) {
for (int i = 0; i < totalEvents - 1; i++) {
UsageEvents.Event E0 = entry.getValue().get(i);
UsageEvents.Event E1 = entry.getValue().get(i + 1);
if (E1.getEventType() == 1 || E0.getEventType() == 1) {
map.get(E1.getPackageName()).launchCount++;
}
if (E0.getEventType() == 1 && E1.getEventType() == 2) {
long diff = E1.getTimeStamp() - E0.getTimeStamp();
map.get(E0.getPackageName()).timeInForeground += diff;
}
}
}
// If First eventtype is ACTIVITY_PAUSED then added the difference of start_time and Event occuring time because the application is already running.
if (entry.getValue().get(0).getEventType() == 2) {
long diff = entry.getValue().get(0).getTimeStamp() - start_time;
map.get(entry.getValue().get(0).getPackageName()).timeInForeground += diff;
}
// If Last eventtype is ACTIVITY_RESUMED then added the difference of end_time and Event occuring time because the application is still running .
if (entry.getValue().get(totalEvents - 1).getEventType() == 1) {
long diff = end_time - entry.getValue().get(totalEvents - 1).getTimeStamp();
map.get(entry.getValue().get(totalEvents - 1).getPackageName()).timeInForeground += diff;
}
}
smallInfoList = new ArrayList<>(map.values());
// Concatenating data to show in a text view. You may do according to your requirement
for (AppUsageInfo appUsageInfo : smallInfoList)
{
// Do according to your requirement
strMsg = strMsg.concat(appUsageInfo.packageName + " : " + appUsageInfo.launchCount + "\n\n");
}
TextView tvMsg = findViewById(R.id.MA_TvMsg);
tvMsg.setText(strMsg);
} else {
Toast.makeText(context, "Sorry...", Toast.LENGTH_SHORT).show();
}
}
AppUsageInfo.class
import android.graphics.drawable.Drawable;
class AppUsageInfo {
Drawable appIcon; // You may add get this usage data also, if you wish.
String appName, packageName;
long timeInForeground;
int launchCount;
AppUsageInfo(String pName) {
this.packageName=pName;
}
}
如何自定义这些代码以收集每 1 小时的数据?
如要获取每小时数据,请更改每小时数据的end_time
和start_time
值。例如:如果我尝试收集过去每小时的数据(对于过去 2 小时的数据)。 我会做以下事情。
long end_time = System.currentTimeMillis();
long start_time = end_time - (1000*60*60);
getUsageStatistics(start_time, end_time);
end_time = start_time;
start_time = start_time - hour_in_mil;
getUsageStatistics(start_time, end_time);
但是,您可以使用Handler
跳过重复写入start_time
和end_time
来更改这些变量的值。每次采集一小时数据,完成一个任务,自动改变变量值后,再次调用getUsageStatistics
方法
注意:也许,您将无法检索过去 7.5 天以上的数据,因为 events are only kept by the system for a few days。
Calendar cal = (Calendar) Calendar.getInstance().clone();
//I used this and it worked, only for 7 days and a half ago
if (daysAgo == 0) {
//Today - I only count from 00h00m00s today to present
end = cal.getTimeInMillis();
start = LocalDate.now().toDateTimeAtStartOfDay().toInstant().getMillis();
} else {
long todayStartOfDayTimeStamp = LocalDate.now().toDateTimeAtStartOfDay().toInstant().getMillis();
if (mDaysAgo == -6) {
//6 days ago, only get events in time -7 days to -7.5 days
cal.setTimeInMillis(System.currentTimeMillis());
cal.add(Calendar.DATE, daysAgo + 1);
end = cal .getTimeInMillis();
start = end - 43200000;
} else {
//get events from 00h00m00s to 23h59m59s
//Current calendar point to 0h0m today
cal.setTimeInMillis(todayStartOfDayTimeStamp);
cal.add(Calendar.DATE, daysAgo + 1);
end = calendar.getTimeInMillis();
cal.add(Calendar.DATE, -1);
start = calendar.getTimeInMillis();
}
}