You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取Android应用的实时使用时长统计

解决Android应用实时获取当日使用时长的问题

问题根源

系统的UsageStatsManager不会实时更新应用的使用时长数据,它是周期性批量同步统计结果的。所以当应用在前台运行时,直接调用queryUsageStats获取的是上次同步的数值,不会实时增长,只有当应用切换前后台或系统完成同步后,数值才会更新。


解决方案

方案一:自行监听应用前后台状态,实时统计时长

通过监听应用的Activity生命周期,判断应用是否处于前台,记录进入前台的时间,实时计算当前前台运行时长,再结合UsageStats的历史数据得到当日总时长,这种方式实时性最强。

步骤1:自定义Application类,注册生命周期回调

public class MyApp extends Application {
    private boolean isAppForeground = false;
    private long foregroundStartTime = 0;
    private long totalForegroundTime = 0; // 本次启动以来累计的前台时长

    @Override
    public void onCreate() {
        super.onCreate();
        registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
            @Override
            public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {}

            @Override
            public void onActivityStarted(@NonNull Activity activity) {
                // 应用从后台切到前台时,记录起始时间
                if (!isAppForeground) {
                    isAppForeground = true;
                    foregroundStartTime = System.currentTimeMillis();
                }
            }

            @Override
            public void onActivityResumed(@NonNull Activity activity) {}

            @Override
            public void onActivityPaused(@NonNull Activity activity) {}

            @Override
            public void onActivityStopped(@NonNull Activity activity) {
                // 确认所有Activity都进入后台,才标记应用退到后台
                if (isAppForeground && !isAnyActivityVisible()) {
                    isAppForeground = false;
                    totalForegroundTime += System.currentTimeMillis() - foregroundStartTime;
                }
            }

            @Override
            public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {}

            @Override
            public void onActivityDestroyed(@NonNull Activity activity) {}
        });
    }

    // 判断当前是否有本应用的Activity处于前台
    private boolean isAnyActivityVisible() {
        ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(1);
        if (!tasks.isEmpty()) {
            ComponentName topActivity = tasks.get(0).topActivity;
            return topActivity.getPackageName().equals(getPackageName());
        }
        return false;
    }

    // 获取当日总使用时长:历史统计时长 + 本次累计时长 + 当前前台运行时长
    public long getTodayTotalUsageTime() {
        long currentTime = System.currentTimeMillis();
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        long dayStart = calendar.getTimeInMillis();

        // 从UsageStats获取当日历史使用时长
        UsageStatsManager usm = (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE);
        List<UsageStats> statsList = usm.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, dayStart, currentTime);

        long historicalTime = 0;
        for (UsageStats stats : statsList) {
            if (stats.getPackageName().equals(getPackageName())) {
                historicalTime = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q 
                    ? stats.getTotalTimeVisible() 
                    : stats.getTotalTimeInForeground();
                break;
            }
        }

        // 计算当前正在前台运行的时长
        long currentForegroundTime = isAppForeground ? System.currentTimeMillis() - foregroundStartTime : 0;

        return historicalTime + totalForegroundTime + currentForegroundTime;
    }
}

步骤2:在MainActivity中调用统计方法

Handler handler = new Handler(getMainLooper());
handler.post(new Runnable() {
    @Override
    public void run() {
        long totalUsage = ((MyApp) getApplication()).getTodayTotalUsageTime();
        Log.d("MainActivity", "Usage time: " + totalUsage);
        handler.postDelayed(this, 1000);
    }
});

方案二:通过UsageEvents获取细粒度状态事件

使用UsageStatsManager.queryEvents获取应用的前后台切换事件,通过事件时间戳计算实时时长,这种方式依赖系统事件记录,无需自行维护生命周期。

Handler handler = new Handler(getMainLooper());
handler.post(new Runnable() {
    @Override
    public void run() {
        long currentTime = System.currentTimeMillis();
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        long dayStart = calendar.getTimeInMillis();

        UsageStatsManager usm = (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE);
        UsageEvents events = usm.queryEvents(dayStart, currentTime);

        long totalTime = 0;
        long lastForegroundTs = 0;
        boolean isForeground = false;
        UsageEvents.Event event = new UsageEvents.Event();

        // 遍历所有事件,计算前台时长
        while (events.hasNextEvent()) {
            events.getNextEvent(event);
            if (event.getPackageName().equals(getPackageName())) {
                if (event.getEventType() == UsageEvents.Event.MOVE_TO_FOREGROUND) {
                    lastForegroundTs = event.getTimeStamp();
                    isForeground = true;
                } else if (event.getEventType() == UsageEvents.Event.MOVE_TO_BACKGROUND) {
                    if (isForeground) {
                        totalTime += event.getTimeStamp() - lastForegroundTs;
                        isForeground = false;
                    }
                }
            }
        }

        // 如果当前应用在前台,加上从最后一次进入前台到现在的时长
        if (isForeground) {
            totalTime += currentTime - lastForegroundTs;
        }

        Log.d("MainActivity", "Usage time: " + totalTime);
        handler.postDelayed(this, 1000);
    }
});

注意事项

  1. 两种方案都需要申请android.permission.PACKAGE_USAGE_STATS权限,并且需要引导用户在设置 > 应用 > 权限管理 > 使用权限访问中开启对应权限。
  2. Android 10及以上版本,应用在后台时Handler可能被系统暂停,若需要后台持续统计,建议使用WorkManager或前台服务实现。
  3. 方案一的自行统计方式可靠性更高,实时性强;方案二依赖系统事件,可能存在少量延迟。

内容的提问来源于stack exchange,提问作者sarthak pawar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 06:05:05