Android中应用前后台切换监听的实现详解
作者:TAKWOLF 发布时间:2021-12-28 17:59:36
前言
最近在工作中遇到了这么一个需求:如何实现 Android 应用前后台切换的监听?下面来一起看看详细的介绍:
iOS 内边是可以实现的,AppDelegate 给了一个回调监听:
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
}
我保留了系统注释。一个iOS应用周期,大概的流程是这样的。
应用从前台进入到后台:
applicationWillResignActive() -> applicationDidEnterBackground()
应用从后台恢复到前台:
applicationWillEnterForeground() -> applicationDidBecomeActive()
Android 中也存在 Application,但是并没有提供前后台切换的监听。
倒不如说,在 Android 中,压根就没有应用前后台的概念。
Android 中基本页面单位是 Activity。
Activity 有自己的生命周期,但是 Application 却没有一个整体的生命周期。
我们可以通过监听 Activity 的生命周期,来模拟实现一个 Application 的生命周期。
Activity 的生命周期不在阐述,写过 Android 的都应该知道。
我们假设现在有两个 Activity 分别是 A 和 B,A 是启动页面,那么生命周期回调是这样的:(我们忽略掉一些不关心的回调)
A 被启动或者 A 进入前台
A.onStart()
A.onResume()
从 A 跳转到 B:
A.onPause()
B.onStart()
B.onResume()
A.onStop()
从 B 返回 A:
B.onPause()
A.onStart()
A.onResume()
B.onStop()
A 被关闭或者 A 进入后台
A.onPause()
A.onStop()
注意上面两个页面回调的启动顺序。
onResume 和 onPause 是一组,两个页面之间是顺序调用。
onStart 和 onStop 是一组,两个页面之间是交叉调用。
也就是说,A 启动到 B,会先调用 B.onStart()
,然后再调用 A.onStop()
;而 B 返回 A 则是相反的,会先调用 A.onStart()
,然后再调用 B.onStop()
。
利用这个特性,我们可以做一个全局计数器,来记录前台页面的数量,在所有 Activity.onStart()
中计数器 +1,在所有 Activity.onStop()
中计数器 -1。计数器数目大于0,说明应用在前台;计数器数目等于0,说明应用在后台。计数器从1变成0,说明应用从前台进入后台;计数器从0变成1,说明应用从后台进入前台。
有了思路,我们来实现。
Application 提供了一个 * 用于监听整个应用中 Activity 声明周期:Application.ActivityLifecycleCallbacks
。
这个 * 要求 API >= 14。对应 API < 14 的情况,可以通过编写一个 BaseActivity,然后让所有的 Activity 都集成这个类来实现整个应用 Activity 声明周期的监听,效果是相同的。
API >= 14,实现如下:
public class ApplicationListener implements Application.ActivityLifecycleCallbacks {
private int foregroundCount = 0; // 位于前台的 Activity 的数目
@Override
public void onActivityStarted(final Activity activity) {
if (foregroundCount <= 0) {
// TODO 这里处理从后台恢复到前台的逻辑
}
foregroundCount++;
}
@Override
public void onActivityStopped(Activity activity) {
foregroundCount--;
if (foregroundCount <= 0) {
// TODO 这里处理从前台进入到后台的逻辑
}
}
/*
* 下面回调,我们都不需要
*/
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {}
@Override
public void onActivityResumed(Activity activity) {}
@Override
public void onActivityPaused(Activity activity) {}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {}
@Override
public void onActivityDestroyed(Activity activity) {}
}
我们在 Application 中注册这个 * 来发挥效果:
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(new ApplicationListener());
}
}
对于 API < 14 的情况,BaseActivity 实现如下:
public class BaseActivity extends AppCompatActivity {
private static int foregroundCount = 0; // 注意是个静态变量
@Override
protected void onStart() {
super.onStart();
if (foregroundCount <= 0) {
// TODO 这里处理从后台恢复到前台的逻辑
}
foregroundCount++;
}
@Override
protected void onStop() {
foregroundCount--;
if (foregroundCount <= 0) {
// TODO 这里处理从前台进入到后台的逻辑
}
super.onStop();
}
}
来源:http://blog.takwolf.com/2017/06/29/android-application-foreground-and-background-switch-listener/


猜你喜欢
- 1、简介应客户要求为了是特殊定制的系统更具安全,系统ROM需要使用自己定义的签名,还有一些特殊的场景也会更改系统的签名比如在过cts认证测试
- 本文实例讲述了java实现基于SMTP发送邮件的方法。分享给大家供大家参考。具体实现方法如下:import java.util.Date;i
- 本文实例为大家分享了android点击按钮切换不同布局的具体代码,供大家参考,具体内容如下先上效果图:如图所示,实现点击下面的按钮切换不同的
- SWF Tools 是一组用来处理 Flash 的 swf 文件的工具包,包括:1. 合并工具 swfcombine2. 抽取工具 swfe
- 本文介绍了spring整合JMS实现同步收发消息(基于ActiveMQ的实现),分享给大家,具体如下:1. 安装ActiveMQ注意:JDK
- 网上汗牛充栋的文章都是介绍Android远程服务的,一个个将Binder机制、AIDL讲得头头是道,然而没有几个人能够给出清晰的范例说明如何
- 点击按钮,先自动进行下拉刷新,也可以手动刷新,刷新完后,最后就多一行数据。有四个选项卡。前两天导师要求做一个给本科学生预定机房座位的app,
- 学过Spring的小伙伴对于IOC一定不陌生,IOC:控制反转(Inversion of Control,英文缩写为IoC)是一个重要的面向
- 本文实例讲述了C#文件分割的方法。分享给大家供大家参考。具体如下:1. 小文件分割(适用于小于等于64M的文件):using System;
- 在idea中将创建的java web项目部署到Tomcat中采用的工具idea 2018.3.6 Tomcat71.先创建第一个新项目sec
- 今天在使用Nlog的时候,发现了一个之前没注意的问题。以前,我的app配置文件都是这么写的,当然配置比较多的时候会改用xml。 如
- SpringBoot项目上传图片一般是上传至远程服务器存储,开发过程中可能会上传至当前项目的某个静态目录中,此时就会遇到这个问题,文件在上传
- 本文实例讲述了java使用Jdom实现xml文件写入操作的方法。分享给大家供大家参考,具体如下:package com.yanek.demo
- 实现官方文档说明:com.baomidou.mybatisplus.annotations.TableFieldTableField注解新增
- 前言最近接了一个项目,甲方不愿意买服务器,但是呢,项目又必须要用文件功能。所以很巧,最近又刚好看到了Minio这个牛逼的工具。正好借此机会记
- 前言这篇博客学习下Mybatis操作中使用Redis做缓存。这里其实主要学习几个注解:@CachePut、@Cacheable、@Cache
- 引言 在c#中,可能大多数人针对于多线程之间的通讯,是熟能生巧,对于AsyncLocal 和Thre
- 我们还是用一个小例子来看看自定义View和自定义属性的使用,带大家来自己定义一个带进度的圆形进度条,我们还是先看一下效果吧从上面可以看出,我
- 说明Druid是Java语言中最好的数据库连接池。Druid能够提供强大的监控和扩展功能。DruidDataSource支持的数据库:理论上
- 一、简介:开发中在用户注册或找回密码之类的功能,经常会遇到获取短信验证码,获取验证码后需要等待1分钟倒计时,这段时间是不能再次发送短信请求的