Android - Application

本文介绍了Android应用中关键生命周期方法如onCreate、onTerminate、onLowMemory等的使用场景,强调了在多进程中处理Application重复创建的问题,并提到了onTrimMemory和onConfigurationChanged的用途。

一、概念

1.1 生命周期

onCreate()
在创建应用程序时调用。可以重写这个方法来实现实例化应用程序单态,以及创建和实例化任何程序状态变量和共享资源。
onTerminate()终止应用程序时调用,不能保证一定会被调用。
onLowMemory()
当系统处于资源匮乏的时候,具有良好行为的应用程序可以释放额外的内存。这
个方法一般只会在后台进程已经终止,但是前台应用程序仍然缺少内存时调用。可以重写这个处理程序来清空缓存或释放不必要的资源。
onTrimMemory()
作为onLowMemory的一个特定于应用程序的替代选择,在Android4.0时引
入。当运行时决定当前应用程序应该尝试减少其内存开销时调用,它包含一个level参数,用于提供请求 的上下文。
onConfigurationChanged()
Activity不同,在配置改变时,应用程序对象不会被终止和重启。
如果应用程序使用的值依赖于特定的配置,则重写这个方法来重新加载这些值,或在应用程序级别处理
配置改变。

二、使用

2.1 全局监听 Activity 生命周期

        监听整个应用进程中所有 Activity 的生命周期变化。无论 Activity 是自己写的还是 sdk 的,只要它运行在你的进程里,它的生命周期回调都会被这个监听器捕获。解耦了 BaseActivity,提供上帝视角的生命周期感知,实现热启动监听、全局栈管理的最佳方案。

        可以注册多个 ActivityLifecycleCallbacks 实例。在 Application 内部,它维护了一个 ArrayList<ActivityLifecycleCallbacks>,注册时只是把监听器添加到列表里。当生命周期事件触发时,Application 会遍历列表依次调用所有注册的监听器。因此不要把所有逻辑(栈管理、打点、业务检查)都塞进同一个监听器中,后期会难以维护。

  • 多进程问题:Application.onCreate 会在每个进程创建时执行。如果App 有多个进程(比如推送进程、小程序进程),务必判断 if (isMainProcess),否则监听逻辑会在每个进程里都跑一遍,导致重复上报或逻辑错误。
  • 初始化顺序:一定要在 Application.onCreate() 中靠前注册,如果注册晚了(比如在 SplashActivity 之后),可能会漏掉第一个页面的 onCreate 回调。
val activityLifecycleCallbacks = object : ActivityLifecycleCallbacks {
    override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {}
    override fun onActivityStarted(activity: Activity) {}
    override fun onActivityResumed(activity: Activity) {}
    override fun onActivityPaused(activity: Activity) {}
    override fun onActivityStopped(activity: Activity) {}
    override fun onActivityDestroyed(activity: Activity) {}
    override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}
}

override fun onCreate() {
    registerActivityLifecycleCallbacks(activityLifecycleCallbacks)
}

unregisterActivityLifecycleCallbacks(activityLifecycleCallbacks)

2.1.1 判断 APP 前后台切换

通过计算“处于 Started 状态的 Activity 数量”,可以判断 APP 是进入了前台还是切到了后台。onActivityStarted: 计数器 +1, onActivityStopped: 计数器 -1, 如果计数从 0 变 1 App 进入前台(冷启动/热启动),如果计数从 1 变 0 App 进入后台。这种方式比监听 ON_START 事件更底层,不依赖 Jetpack 库,且兼容性极好。

private var activityCount = 0
private val callback = object : ActivityLifecycleCallbacks {
    override fun onActivityStarted(activity: Activity) {
        activityCount++
        if (activityCount == 1) {
            // APP回到前台:检查更新、同步配置、上报活跃日志
        }
    }
    override fun onActivityStopped(activity: Activity) {
        activityCount--
        if (activityCount == 0) {
            // APP 进入后台
        }
    }
}

2.1.2 Activity栈管理(一键退出)

        有时候需要“退出登录”,要求关闭所有页面并回到登录页。如果手动 finish() 很容易漏掉某个中间页。可以用一个 List 维护所有活着的 Activity。

        当屏幕旋转时 Activity 会销毁重建,onActivityDestroyed -> onActivityCreated,如果 StackManager 逻辑不够健壮,可能会导致引用了已经销毁的 Activity。

private val activityStack = Stack<Activity>()
private val callback = object : ActivityLifecycleCallbacks {
    override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
        activityStack.push(activity)
    }
    override fun onActivityDestroyed(activity: Activity) {
        activityStack.remove(activity)
    }
}

fun finishAllActivity() {
    for (activity in activityStack) {
        if (!activity.isFinishing) {
            activity.finish()
        }
    }
    activityStack.clear()
}

2.2 多进程下Application多次创建问题

通常会将一些初始化代码放在 Application 中,而每当运行指定了进程的组件时都会新建一个 Application 对象,由于不是同一个所以数据不通用,只需要在 Application 类中对当前进程加以判断即可。

override fun onCreate() {
    super.onCreate()
    if (isMainProcess()) init() //确保在主进程下才初始化(多进程会导致Application重复创建)
}
/**
 * 当前进程是否为主进程
 */
private fun isMainProcess(): Boolean {
    val activityManager = getSystemService(ACTIVITY_SERVICE) as ActivityManager
    val runningProcesses = activityManager.runningAppProcesses
    if (runningProcesses != null) {
        for (process in runningProcesses) {
            if (packageName.equals(process.processName)) {
                return true
            }
        }
    }
    return false
}

2.3 无埋点页面统计

要统计每个页面的访问次数和停留时长,如果让每个 Activity 自己去上报,代码会非常冗余。利用 LifecycleCallbacks,可以在一个地方搞定全应用统计。

private val callback = object : ActivityLifecycleCallbacks {
    override fun onActivityResumed(activity: Activity) {
        // 开始计时
        PageTracker.startRecord(activity.javaClass.simpleName)
    }

    override fun onActivityPaused(activity: Activity) {
        // 结束计时并上报
        PageTracker.stopRecordAndReport(activity.javaClass.simpleName)
    }
}

三、其它

3.1 getApplication() 和 getApplicationContext() 区别?

获得的对象相同,作用域不同(语义的区别,getApplication() 只在 Activity 和 Service 中有,在别的地方获取例如 BroadcastReceiver 中就要使用 getApplicationContext() 了)。getBaseContext() 获取的是 ContextImpl。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值