1.前言
在进行14.0的系统定制开发中,在某些app的定制过程中,需要知道某个app的启动时候然后获取 应用使用时长的功能,所以就需要监听某个app的启动后就获取使用时长,需要在Activity的生命周期中来实现监听功能
2.frameworks监听某个app启动获取应用使用时长功能实现的核心类
frameworks\base\core\java\android\app\Activity.java3.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的运行时间了 从而来实现了相关的功能