【问题标题】:Android: get UsageStats per hourAndroid:每小时获取 UsageStats
【发布时间】:2020-07-17 15:09:13
【问题描述】:

我使用Android的UsageStats功能,但最小的间隔是DAILY INTERVAL

long time = System.currentTimeMillis();
List<UsageStats> appList = manager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - DAY_IN_MILLI_SECONDS, time);

如何以每小时为间隔获得UsageStats

【问题讨论】:

  • 所以你需要每小时运行一次代码..
  • 我读到即使您选择的时间范围持续五分钟,如果您选择 INTERVAL_WEEKLY 作为间隔类型,您将获得该间隔内的所有统计数据。
  • @Rougher 你的问题解决了吗?如果我现在提供正确答案,对您有帮助吗?我在这方面做了很多工作。
  • 嘿@SabbirAhmed。我仍在寻找解决方案。我们将不胜感激。
  • @Rougher 好的,我会尽力帮助你的。

标签: java android usage-statistics


【解决方案1】:

所有功劳归this answer。我从那个人那里学到了。

我们如何收集自定义时间范围内的应用使用数据(例如每 1 小时)?

我们必须调用queryEvents(long begin_time, long end_time) 方法,因为它会为我们提供从begin_timeend_time 的所有数据。它通过foregroundbackground 事件为我们提供每个应用程序数据,而不是像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_timestart_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_timeend_time 以更改这些变量的值。每次采集数据一小时,完成一个任务,自动更改变量值后,再次调用getUsageStatistics方法。

注意:您可能无法以events are only kept by the system for a few days 检索超过过去 7.5 天的数据。

【讨论】:

  • @SabbirAhmedת 伟大的解决方案!由于 API 29 中的弃用,我只将 UsageEvents.Event.MOVE_TO_FOREGROUND 更改为 UsageEvents.Event.ACTIVITY_RESUMED,将 UsageEvents.Event.MOVE_TO_BACKGROUND 更改为 UsageEvents.Event.ACTIVITY_PAUSED
  • @Rougher 很高兴为您提供帮助。还要感谢您提供此信息(API 29 中已弃用)。
【解决方案2】:
    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();
        }
    }

【讨论】:

    【解决方案3】:

    我认为不可能,即使你在一个区间的中间请求数据,看起来数据是存储在桶中的,最小桶是一天。 在UsageStatsManager 文档中,它说:

    在时间间隔中间的数据请求将包括该时间间隔。

    另外,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;
    

    【讨论】:

    • 我在 cmets 中为我的帖子写的。
    【解决方案4】:

    是的,Android 提供最低限度的INTERVAL_DAILY。但为了获得最佳效果,您可以使用INTERVAL_BEST。 Android 在queryUsageStats(int, long, long) 的给定时间范围内提供最佳间隔计时器。

    编码愉快...

    【讨论】:

    • 我看到了INTERVAL_BEST,但我不明白我怎么知道间隔是多少?我希望每小时得到类似:whatsapp - 30 分钟,youtube - 25 分钟,facebook - 5 分钟。
    猜你喜欢
    • 1970-01-01
    • 2020-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-26
    • 1970-01-01
    • 1970-01-01
    • 2018-05-11
    相关资源
    最近更新 更多