news 2026/4/23 5:05:41

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/23 9:22:44

基于Java的售卖智慧管理系统的设计与实现全方位解析:附毕设论文+源代码

1. 为什么这个毕设项目值得你 pick ? 《基于Java的售卖智慧管理系统的设计与实现》针对传统选题“烂大街”的问题&#xff0c;选择了一个在功能模块化设计上独具匠心、开发难度适中的题目。系统涵盖了客户管理、产品管理、订单管理等20余种核心业务模块&#xff0c;结合普通员…

作者头像 李华
网站建设 2026/4/23 9:20:22

MySQL 经典15问

问题1&#xff1a;为什么项目不能用Map或文本文件存数据&#xff0c;非要用数据库&#xff1f;刚入行的小闵用Java的Map存学生信息&#xff0c;服务器重启后500条数据全丢——因为内存数据不持久化&#xff1b;换成文本文件存储后&#xff0c;又要为甲方的每一个查询需求写大量…

作者头像 李华
网站建设 2026/4/23 12:23:29

介观交通流仿真软件:VISSIM (介观模式)_(12).介观模式下的交通事件管理

介观模式下的交通事件管理 在介观交通流仿真软件中&#xff0c;交通事件的管理是仿真过程中的一个重要环节。交通事件可以包括交通事故、交通信号灯故障、道路封闭、临时交通管制等。这些事件对交通流的影响是多方面的&#xff0c;可能会导致交通拥堵、延误等问题。因此&#x…

作者头像 李华
网站建设 2026/4/23 10:50:25

基于django智能推荐算法的全屋定制平台网站设计实现

背景分析家居定制行业正经历从标准化向个性化需求的转型&#xff0c;消费者对空间利用率、风格匹配度的要求日益提升。传统定制方案依赖人工设计&#xff0c;存在效率低、风格局限性强、成本高等痛点。Django框架结合智能推荐算法可构建数据驱动的解决方案&#xff0c;通过用户…

作者头像 李华
网站建设 2026/4/23 14:01:33

django用Python设计自主学习系统后端设计实现

Django框架在自主学习系统中的优势Django作为Python的高效Web框架&#xff0c;具备快速开发、安全性和可扩展性特性&#xff0c;适合构建复杂系统。其内置的ORM简化数据库操作&#xff0c;模板引擎支持动态内容渲染&#xff0c;而自动化管理后台可减少基础代码编写。这些特性为…

作者头像 李华
网站建设 2026/4/23 12:22:18

迅雷Android开发工程师面试指南

迅雷网络 资深android开发工程师 职位描述 Java架构设计/优化浏览器Android客户端产品研发架构设计能力Webview计算机/软件工程相关专业小说漫画阅读Kotlin 岗位职责 1、负责浏览器应用的功能开发,维护和问题修复,重点关注WebView组件的稳定性和体验提升; 2、负责浏览器应用…

作者头像 李华