我正在尝试从UsageStats
查询UsageStatsManager
,目的是返回每天使用的所有应用包以及持续多长时间。
守则:
public static List<UsageStats> getUsageStatsList(Context context){
UsageStatsManager usm = getUsageStatsManager(context);
Calendar calendar = Calendar.getInstance();
long endTime = calendar.getTimeInMillis();
calendar.add(Calendar.DAY_OF_YEAR, -1);
long startTime = calendar.getTimeInMillis();
List<UsageStats> usageStatsList = usm.queryUsageStats(UsageStatsManager.INTERVAL_DAILY,startTime, endTime);
return usageStatsList;
}
我有一个警报,每天在午夜之前触发并查询使用状态,然后存储返回的数据。起初一切似乎工作正常,我得到包结果和他们的活动时间,但是我添加了一个功能,每小时检查一次结果,这是我发现一个奇怪的发现。
来自UsageStatsManager
的结果似乎是在不同的时间重置,而不是在午夜,这是我在考虑使用INTERVAL_DAILY
作为搜索参数时的预期。
根据我保存的数据包“时间”结果似乎正在重置(粗略时间):
我意识到包装时间重置之间存在相关性,但这是否意味着发生?
我已经看过以下帖子了,这是我收集了大量信息的地方: How to use UsageStatsManager?
因此:
Android UsageStatsManager producing wrong output?
在评论中提到从queryUsageStats
返回的数据不可信并且返回随机结果。
我是否遗漏了一些简单或UsageStatsManager
无法正常运作的内容?
答案 0 :(得分:6)
我也注意到了API 21中的这种行为,在API 21中,UsageStats数据的维护时间不长。它在API 22中运行良好。如果您签入android /data/system/usagestats
,您会在API 21中找到有限的条目,所以在API 21中使用它是不可靠的。
对于API 21+,
根据{{1}} API查询usagestats
时,您将获得全天INTERVAL_DAILY
。
如果你想在一天中的几小时内查询,你应该使用UsageStatsManager
并按照你自己的逻辑迭代它们。
我尝试了以下方式...
这是捕获每个应用程序数据的模态类:
queryEvents
private class AppUsageInfo {
Drawable appIcon;
String appName, packageName;
long timeInForeground;
int launchCount;
AppUsageInfo(String pName) {
this.packageName=pName;
}
}
这里是方法,它很容易,顺其自然:
List<AppUsageInfo> smallInfoList; //global var
答案 1 :(得分:3)
我想我发现那里发生了什么。首先我写了下面的代码,
public String getDaily(String appPackageName, long startTime, long endTime)
{
List<UsageStats> usageStatsList = usageStatsManager.queryUsageStats(
UsageStatsManager.INTERVAL_DAILY, startTime,endTime);
String x="";
for(int i=0; i<usageStatsList.size(); i++) {
UsageStats stat = usageStatsList.get(i);
if(stat.getPackageName().equals(appPackageName))
x=x+i+"-"+stat.getPackageName()+"-"
+converLongToTimeChar(stat.getTotalTimeInForeground())+"\n";
}
return x;
}
public String converLongToTimeChar(long usedTime) {
String hour="", min="", sec="";
int h=(int)(usedTime/1000/60/60);
if (h!=0)
hour = h+"h ";
int m=(int)((usedTime/1000/60) % 60);
if (m!=0)
min = m+"m ";
int s=(int)((usedTime/1000) % 60);
if (s==0 && (h!=0 || m!=0))
sec="";
else
sec = s+"s";
return hour+min+sec;
}
(今天的日期是03.08.2017 00:25:14) 当我发送时(“包名”,02.08.2017 00.00.00,03.08.2017 00.00.00);方法,(我用日历发送这个日期,你可以在谷歌搜索,如何设置这样的日期) 我得到了这个输入;
46-'apppackagename'-9m 31s
154-'apppackagename'-22m 38s
然后我发送了(“包名”,03.08.2017 00.00.00,04.08.2017 00.00.00);方法, 我得到了这个输入;
25-'apppackagename'-22m 38s
我使用了方法发送的app大约1分钟。我发送的方法输出再次是:
02:08:2017-03.08.2017
46-'apppackagename'-9m 31s
154-'apppackagename'-23m 32s
03:08:2017-04.08.2017
25-'apppackagename'-23m 32s
如你所见,他们两者都增加了。我看到我等到凌晨03.00, 我使用app大约5分钟,我得到了这些输出。
02:08:2017-03.08.2017
46-'apppackagename'-9m 31s
154-'apppackagename'-23m 32s
03:08:2017-04.08.2017
25-'apppackagename'-23m 32s
50-'apppackagename'-4m 48s
总而言之,你应该在白天及其最后一个前台运行时间之前控制。如果它与当天的第一个前景时间相同。你应该消除那个时间并返回其他人的总和。 (即使我不知道那个奇怪的系统。)新的一天的计数器在03:00之后开始。
我希望它会对你有所帮助。
答案 2 :(得分:3)
我同意您提到的关于queryUsageStats
不是可靠来源的评论中所说的内容。我一直在玩UsageStatsManager
一段时间,它会根据一天中的时间返回不一致的结果。我发现使用UsageEvent
并手动计算必要的信息要更加值得信赖(至少对于每日统计数据),因为它们是时间点,并且没有任何奇怪的计算错误会产生不同的根据一天中的时间输出相同的输入。
我使用@ Vishal提出的解决方案来提出我自己的解决方案:
/**
* Returns the stats for the [date] (defaults to today)
*/
fun getDailyStats(date: LocalDate = LocalDate.now()): List<Stat> {
// The timezones we'll need
val utc = ZoneId.of("UTC")
val defaultZone = ZoneId.systemDefault()
// Set the starting and ending times to be midnight in UTC time
val startDate = date.atStartOfDay(defaultZone).withZoneSameInstant(utc)
val start = startDate.toInstant().toEpochMilli()
val end = startDate.plusDays(1).toInstant().toEpochMilli()
// This will keep a map of all of the events per package name
val sortedEvents = mutableMapOf<String, MutableList<UsageEvents.Event>>()
// Query the list of events that has happened within that time frame
val systemEvents = usageManager.queryEvents(start, end)
while (systemEvents.hasNextEvent()) {
val event = UsageEvents.Event()
systemEvents.getNextEvent(event)
// Get the list of events for the package name, create one if it doesn't exist
val packageEvents = sortedEvents[event.packageName] ?: mutableListOf()
packageEvents.add(event)
sortedEvents[event.packageName] = packageEvents
}
// This will keep a list of our final stats
val stats = mutableListOf<Stat>()
// Go through the events by package name
sortedEvents.forEach { packageName, events ->
// Keep track of the current start and end times
var startTime = 0L
var endTime = 0L
// Keep track of the total usage time for this app
var totalTime = 0L
// Keep track of the start times for this app
val startTimes = mutableListOf<ZonedDateTime>()
events.forEach {
if (it.eventType == UsageEvents.Event.MOVE_TO_FOREGROUND) {
// App was moved to the foreground: set the start time
startTime = it.timeStamp
// Add the start time within this timezone to the list
startTimes.add(Instant.ofEpochMilli(startTime).atZone(utc)
.withZoneSameInstant(defaultZone))
} else if (it.eventType == UsageEvents.Event.MOVE_TO_BACKGROUND) {
// App was moved to background: set the end time
endTime = it.timeStamp
}
// If there's an end time with no start time, this might mean that
// The app was started on the previous day, so take midnight
// As the start time
if (startTime == 0L && endTime != 0L) {
startTime = start
}
// If both start and end are defined, we have a session
if (startTime != 0L && endTime != 0L) {
// Add the session time to the total time
totalTime += endTime - startTime
// Reset the start/end times to 0
startTime = 0L
endTime = 0L
}
}
// If there is a start time without an end time, this might mean that
// the app was used past midnight, so take (midnight - 1 second)
// as the end time
if (startTime != 0L && endTime == 0L) {
totalTime += end - 1000 - startTime
}
stats.add(Stat(packageName, totalTime, startTimes))
}
return stats
}
// Helper class to keep track of all of the stats
class Stat(val packageName: String, val totalTime: Long, val startTimes: List<ZonedDateTime>)
有几点意见:
Event
所拥有的时间戳以UTC为单位,这就是我将我的开始/结束查询时间从我的默认时区转换为UTC的原因,以及为什么我将开始时间转换回每个事件。这个让我有一段时间...... - 1000
并替换为您想要的任何内容。 Stat
类和代码来捕获您需要的任何信息。例如,如果需要,您可以跟踪结束时间或应用程序在一天内启动的次数。 我希望这有帮助!
答案 3 :(得分:1)
我也遇到了同样的问题,并且为此也向Google开了一个问题。如果https://issuetracker.google.com/issues/118564471符合您的描述,请看看。