我试图从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;
}我有一个闹钟,每天午夜前发出警报,查询其usagestats,然后存储返回的数据。起初,一切看起来都很好,我得到了包结果和它们的活动时间,但是我添加了一个函数,可以每小时检查结果,这里是我做了一个奇怪的发现。
来自UsageStatsManager的结果似乎是在不同的时间重置,而不是在午夜,考虑到我使用INTERVAL_DAILY作为搜索参数,这正是我所期望的。
从我保存的包的数据来看,“时间”结果似乎是在重置(,粗略时间,):
我意识到,当包的时间被重置时,这是有关联的,但这是否意味着会发生呢?
我已经看到了下面的帖子,我从这里获得了很多信息:如何使用UsageStatsManager?
因此:Android UsageStatsManager产生错误的输出?在评论中提到,从queryUsageStats返回的数据不能被信任,并且随机结果正在返回。
我是遗漏了一些简单的东西,还是UsageStatsManager的功能不正常?
发布于 2017-07-28 18:45:52
我也注意到了API 21中的这种行为,UsageStats数据在API 21中的维护时间不够长。它从API 22中运行良好,如果您签入android /data/system/usagestats,您将在API 21中找到有限的条目,因此在API 21中使用它并不可靠。
对于API 21+,您将获得一整天的usagestats,同时根据UsageStatsManager API查询INTERVAL_DAILY。如果您想在一天之内进行查询,您应该使用queryEvents并按照自己的逻辑迭代它们。
我试过以下方法..。
这是用于捕获每个应用程序的数据的模式类:
private class AppUsageInfo {
Drawable appIcon;
String appName, packageName;
long timeInForeground;
int launchCount;
AppUsageInfo(String pName) {
this.packageName=pName;
}
}List<AppUsageInfo> smallInfoList; //global var
这是一种方法,它很简单,随流程而去:
void getUsageStatistics() {
UsageEvents.Event currentEvent;
List<UsageEvents.Event> allEvents = new ArrayList<>();
HashMap<String, AppUsageInfo> map = new HashMap <String, AppUsageInfo> ();
long currTime = System.currentTimeMillis();
long startTime currTime - 1000*3600*3; //querying past three hours
UsageStatsManager mUsageStatsManager = (UsageStatsManager)
mContext.getSystemService(Context.USAGE_STATS_SERVICE);
assert mUsageStatsManager != null;
UsageEvents usageEvents = mUsageStatsManager.queryEvents(usageQueryTodayBeginTime, currTime);
//capturing all events in a array to compare with next element
while (usageEvents.hasNextEvent()) {
currentEvent = new UsageEvents.Event();
usageEvents.getNextEvent(currentEvent);
if (currentEvent.getEventType() == UsageEvents.Event.MOVE_TO_FOREGROUND ||
currentEvent.getEventType() == UsageEvents.Event.MOVE_TO_BACKGROUND) {
allEvents.add(currentEvent);
String key = currentEvent.getPackageName();
// taking it into a collection to access by package name
if (map.get(key)==null)
map.put(key,new AppUsageInfo(key));
}
}
//iterating through the arraylist
for (int i=0;i<allEvents.size()-1;i++){
UsageEvents.Event E0=allEvents.get(i);
UsageEvents.Event E1=allEvents.get(i+1);
//for launchCount of apps in time range
if (!E0.getPackageName().equals(E1.getPackageName()) && E1.getEventType()==1){
// if true, E1 (launch event of an app) app launched
map.get(E1.getPackageName()).launchCount++;
}
//for UsageTime of apps in time range
if (E0.getEventType()==1 && E1.getEventType()==2
&& E0.getClassName().equals(E1.getClassName())){
long diff = E1.getTimeStamp()-E0.getTimeStamp();
phoneUsageToday+=diff; //gloabl Long var for total usagetime in the timerange
map.get(E0.getPackageName()).timeInForeground+= diff;
}
}
//transferred final data into modal class object
smallInfoList = new ArrayList<>(map.values());
}发布于 2018-06-01 16:52:43
我同意您在评论中提到的关于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的原因,以及为什么我将每个事件的开始时间转换回UTC。这个让我有一段时间..。- 1000并用任何您想要的替换。Stat类和代码,以获取所需的任何信息。例如,您可以跟踪结束时间,或者一天内启动应用程序的次数(如果需要)。我希望这能帮到你!
发布于 2017-08-03 11:07:20
我想我找到了那里发生的事。首先我写了下面的代码,
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 :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我使用了我发送的应用程序,大约1分钟。同样,我发送的方法输出是:
02:08:2017-03.08.2017
46-'apppackagename'-9m 31s
154-'apppackagename'-23m 32s03:08:2017-04.08.2017
25-'apppackagename'-23m 32s如你所见,两者都增加了。当我看到我一直等到凌晨3点的时候,我使用了大约5分钟的应用程序,我得到了这些输出。
02:08:2017-03.08.2017
46-'apppackagename'-9m 31s
154-'apppackagename'-23m 32s03:08:2017-04.08.2017
25-'apppackagename'-23m 32s
50-'apppackagename'-4m 48s最后,你应该在一天前和它的最后一个前期运行时间进行控制。İf和那天的第一个前景时间是一样的。你应该去掉这段时间,然后把其他时间的总和还给你。(即使我不知道那个奇怪的系统。)新一天的柜台在凌晨3点后开始。
我希望这对你会有帮助。
https://stackoverflow.com/questions/36238481
复制相似问题