news 2026/4/30 7:39:00

Android 14.0 framework监听某个app启动获取应用使用时长功能实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Android 14.0 framework监听某个app启动获取应用使用时长功能实现

1.前言

在进行14.0的系统定制开发中,在某些app的定制过程中,需要知道某个app的启动时候然后获取 应用使用时长的功能,所以就需要监听某个app的启动后就获取使用时长,需要在Activity的生命周期中来实现监听功能

2.frameworks监听某个app启动获取应用使用时长功能实现的核心类

frameworks\base\core\java\android\app\Activity.java

3.frameworks监听某个app启动获取应用使用时长功能实现的核心功能分析和实现

Android Activity生命周期是Android开发中非常重要的概念,它描述了一个Activity从创建到销毁的整个过程。Activity生命周期由一系列回调方法组成,开发者可以在这些方法中执行相应的操作。

1. Activity生命周期的状态
Activity在其生命周期中会经历以下几种状态:

运行(Running):Activity位于屏幕前台,用户可以与它交互。

暂停(Paused):Activity部分被遮挡,不再处于前台,但仍然可见(例如,有一个透明或非全屏的Activity覆盖在上面)。此时Activity不再接收用户输入。

停止(Stopped):Activity完全被遮挡,不可见。它仍然保留所有状态和成员信息,但可能被系统销毁。

销毁(Destroyed):Activity被系统销毁或从内存中移除。

2. 生命周期回调方法
Activity类提供了以下核心生命周期方法:

onCreate()
调用时机:Activity首次创建时调用。

作用:进行一次性初始化,如加载布局、绑定数据等。

后续状态:onStart()

onStart()
调用时机:Activity即将变为可见时调用(进入前台)。

作用:准备Activity进入前台,但尚未与用户交互。

后续状态:onResume()(如果Activity进入前台)或onStop()(如果Activity被隐藏)

onResume()
调用时机:Activity开始与用户交互之前调用。此时Activity位于Activity栈的顶部。

作用:启动动画、初始化相机等需要与用户交互的组件。

后续状态:onPause()

onPause()
调用时机:当Activity即将进入暂停状态时调用(例如,有另一个非全屏Activity覆盖)。

作用:提交未保存的更改、释放系统资源、停止动画等。注意,此方法应快速执行,否则会影响新Activity的显示。

后续状态:onResume()(如果Activity重新回到前台)或onStop()(如果Activity完全不可见)

onStop()
调用时机:Activity完全不可见时调用。

作用:释放不再需要的资源,保存数据。

后续状态:onRestart()(如果Activity重新显示)或onDestroy()(如果Activity被销毁)

onRestart()
调用时机:Activity从停止状态重新显示时调用,在onStart()之前。

作用:重新初始化在onStop()中释放的资源。

后续状态:onStart()

onDestroy()
调用时机:Activity被销毁之前调用。这可能是因为Activity结束(调用finish())或系统为节省空间而临时销毁该Activity。

作用:释放所有资源,包括线程、数据库连接等。

3. 生命周期图示
为了更好地理解,以下是一个经典的生命周期图示(描述性):

启动Activity:onCreate() -> onStart() -> onResume()

另一个Activity覆盖当前Activity(非全屏):onPause() -> (如果完全覆盖)onStop()

返回原Activity:onRestart() -> onStart() -> onResume()

回退或结束当前Activity:onPause() -> onStop() -> onDestroy()

注意:当系统资源不足时,可能会杀死后台的Activity。此时,当用户返回时,Activity会重新创建。

4. 保存和恢复状态
由于Activity可能被系统销毁,因此需要保存状态以便恢复。

onSaveInstanceState()
在Activity可能被销毁之前调用(例如,屏幕旋转、系统资源回收)。可以将临时数据保存到Bundle中。

onRestoreInstanceState()
在onStart()之后、onResume()之前调用,用于恢复保存的状态。也可以选择在onCreate()中恢复。

5. 实际开发中的注意事项
避免在onPause()和onStop()中执行耗时操作,否则会影响新Activity的响应。

在onResume()中重新获取资源(如相机),在onPause()中释放。

使用onSaveInstanceState()保存临时UI状态,使用onCreate()或onRestoreInstanceState()恢复。

了解配置变更(如屏幕旋转)会销毁并重建Activity,因此需要妥善处理状态保存。

3.1 Activity.java中相关源码分析 ‌

Activity在‌Android应用程序中扮演着核心角色,主要负责展示用户界面、处理用户输入、管理生命周期以及与其他组件进行交互。 展示用户界面: Activity是用户可以看到的一个屏幕,它负责显示应用程序的用户界面,包括布局、按钮、文本框等元素。 用户可以通过与这些界面的交互来完成各种操作。

@MainThread @CallSuper protected void onCreate(@Nullable Bundle savedInstanceState) { if (DEBUG_LIFECYCLE) Slog.v(TAG, "onCreate " + this + ": " + savedInstanceState); if (mLastNonConfigurationInstances != null) { mFragments.restoreLoaderNonConfig(mLastNonConfigurationInstances.loaders); } if (mActivityInfo.parentActivityName != null) { if (mActionBar == null) { mEnableDefaultActionBarUp = true; } else { mActionBar.setDefaultDisplayHomeAsUpEnabled(true); } } .... mRestoredFromBundle = savedInstanceState != null; mCalled = true; } public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) { onCreate(savedInstanceState); } @CallSuper protected void onResume() { if (DEBUG_LIFECYCLE) Slog.v(TAG, "onResume " + this); dispatchActivityResumed(); mActivityTransitionState.onResume(this); enableAutofillCompatibilityIfNeeded(); if (mAutoFillResetNeeded) { if (!mAutoFillIgnoreFirstResumePause) { View focus = getCurrentFocus(); if (focus != null && focus.canNotifyAutofillEnterExitEvent()) { // TODO(b/148815880): Bring up keyboard if resumed from inline authentication. // TODO: in Activity killed/recreated case, i.e. SessionLifecycleTest# // testDatasetVisibleWhileAutofilledAppIsLifecycled: the View's initial // window visibility after recreation is INVISIBLE in onResume() and next frame // ViewRootImpl.performTraversals() changes window visibility to VISIBLE. // So we cannot call View.notifyEnterOrExited() which will do nothing // when View.isVisibleToUser() is false. getAutofillManager().notifyViewEntered(focus); } } } notifyContentCaptureManagerIfNeeded(CONTENT_CAPTURE_RESUME); mCalled = true; } //add core start public boolean isAppRunningState(@Nullable String appPackageName){ ActivityManager activities = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); List<ActivityManager.RunningAppProcessInfo> appProcesses = activities.getRunningAppProcesses(); if (appProcesses == null) { return false; } for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) { Log.e("Activity_Main","appProcess.processName= "+appProcess.processName); if (appProcess.processName.equals(appPackageName)) { return true; } } return false; } private String getappusedtimes(@Nullable String appPackageName){ String usedtimes = ""; UsageStatsManager usageStatsManager = (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE); try { Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.HOUR_OF_DAY, 0); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); List<UsageStats> stats =usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, calendar.getTimeInMillis(), System.currentTimeMillis()); for(int i=0;i<stats.size();i++){ final android.app.usage.UsageStats pkgStats = stats.get(i); String package_name=pkgStats.getPackageName(); long time_begin= pkgStats.getFirstTimeStamp(); long time_end=pkgStats.getLastTimeStamp(); long time_used=pkgStats.getLastTimeUsed(); long time_totals=pkgStats.getTotalTimeInForeground(); if(time_total>0&&package_name.equals(appPackageName)) { Log.e("AppInfoDashboardFragment","package_name:"+package_name+"--time_begin:"+time_begin+"--time_used:"+time_used+"--time_total:"+time_total); return time_totals/1000+"s"; } } } catch (Exception e) { e.printStackTrace(); } return usedtimes; } //add core end @CallSuper protected void onPostResume() { //add core start boolean isRunning = isAppRunningState("com.tel.troops"); android.util.Log.e("Activity_Main","com.tel.troops is run="+isRunning); if(isRunning){ String run_time = getappusedtimes("com.tel.troops"); android.util.Log.e("Activity_Main","com.tel.troops is run_time="+ run_time); } //add core end final Window win = getWindow(); if (win != null) win.makeActive(); if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(true); mCalled = true; }

在上述的Activity.java的相关源码中,在onCreate(@Nullable Bundle savedInstanceState) 中 的相关源码中,主要是初始化布局等功能,而在onPostResume()表示页面已经加载完毕后 调用的相关方法,所以就可以在onPostResume()中,来调用 isAppRunningState("com.tel.troops") 来利用ActivityManager.RunningAppProcessInfo当前置顶运行的进行是否是需要监听的app包名 如果返回true就可以监听到app已经启动了,这时候就可以调用getappusedtimes("com.tel.troops"); 来获取需要监听app的运行时间了,这样就可以监听app启动的时候,来获取这个app的运行时间了 从而来实现了相关的功能

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/27 10:41:27

深度学习框架目标检测算法YOLOV8预训练模型训练海上落水人员及障碍物数据集建立基于深度学习YOLOV8海上落水人员检测系统 海上搜救无人机 - 智慧海事监控平台

海上落水人员及障碍物数据集&#xff0c;有500多张并已经标注好了txt格式。已经划分hao训练集和验证集&#xff0c;可直接训练&#xff0c;【来源自建】 2类【溺水人员&#xff0c;障碍物】11海上落水人员及障碍物检测数据集 的完整 YOLOv8 训练与检测系统方案&#xff0c;包含…

作者头像 李华
网站建设 2026/4/28 21:50:16

springboot美容院管理系统(11523)

有需要的同学&#xff0c;源代码和配套文档领取&#xff0c;加文章最下方的名片哦 一、项目演示 项目演示视频 二、资料介绍 完整源代码&#xff08;前后端源代码SQL脚本&#xff09;配套文档&#xff08;LWPPT开题报告&#xff09;远程调试控屏包运行 三、技术介绍 Java…

作者头像 李华
网站建设 2026/5/1 1:56:07

轻量化深度学习模型(EEGNet)

EEGNet是一种专为脑电图&#xff08;EEG&#xff09;信号处理设计的紧凑型卷积神经网络&#xff08;CNN&#xff09;&#xff0c;核心定位是在资源受限场景下实现高效的脑电信号分类&#xff0c;尤其适用于脑机接口&#xff08;BCI&#xff09;领域。与传统深度学习模型相比&am…

作者头像 李华
网站建设 2026/4/24 20:15:28

PySide6从0开始学习的笔记(十) 样式表(QSS)

PySide6 的样式表&#xff08;Qt Style Sheets&#xff0c;QSS&#xff09;是模仿 CSS 语法的界面美化机制&#xff0c;用于统一控制 PySide6 控件的外观&#xff0c;从基础的颜色、字体到复杂的控件状态、自定义控件样式都能覆盖。一、QSS 基础核心1.1 基本语法结构QSS 语法与…

作者头像 李华
网站建设 2026/4/30 12:05:15

超越`.groupby().agg()`:深度解析Pandas聚合API的现代实践

好的&#xff0c;收到您的需求。我将基于您提供的随机种子&#xff08;1766095200066&#xff09;&#xff0c;深入探讨Pandas聚合API中一些进阶、高效且常被忽视的用法&#xff0c;撰写一篇适合开发者阅读的深度技术文章。 超越.groupby().agg()&#xff1a;深度解析Pandas聚合…

作者头像 李华