Android中应用前后台切换监听的实现详解

前言

最近在工作中遇到了这么一个需求:如何实现 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();
 }
}

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如有疑问大家可以留言交流,谢谢大家对我们的支持。

(0)

相关推荐

  • Android RecyclerView显示Item布局不一致解决办法

    RecyclerView显示Item布局不一致 在自定义RecyclerAdapter的时候,在重写onCreateViewHolder方法是使用了 @Override public H onCreateViewHolder(ViewGroup parent, int viewType) { View view=View.inflate(context,layoutId,null); return view; } 进行生成布局,结果发现生成的布局没有LayoutParams.以前自定义View的

  • Android文件下载功能实现代码

    本文实例为大家分享了Android文件下载功能的具体代码,供大家参考,具体内容如下 1.普通单线程下载文件: 直接使用URLConnection.openStream()打开网络输入流,然后将流写入到文件中! public static void downLoad(String path,Context context)throws Exception { URL url = new URL(path); InputStream is = url.openStream(); //截取最后的文件名

  • Android用Scroller实现一个可向上滑动的底部导航栏

    静静等了5分钟竟不知道如何写我这第一篇文章.每次都想好好的学习学习,有时间多敲敲代码,写几篇自己的文章.今天终于开始实行了,还是有点小激动的.哈哈! 好了废话就不多收了.我今天想实现的一个功能就是一个可以上滑底部菜单栏.为什么我会想搞这么个东西呢, 还是源于一年前,我们app 有这么个需求,当时百度也好谷歌也好,都没有找到想要的效果,其实很简单的一个效果.但是当时我也是真的太菜了,所有有关自定义的控件真的是不会,看别人的代码还好,真要是自己写,一点头绪都没有.因为我试着写了,真的不行啊.当时觉得

  • Android上使用grpc的方法教程

    前言 最近的一个项目使用到了grpc实现跨平台的远程调用,在安卓端使用的时候遇到了一些坑,这里记录一下. 首先根据grpc android的官方Demo配置grpc依赖,测试它的hello world工程. 编译谷歌官方的helloworld工程 添加rotobuf-gradle-plugin插件 首先添加rotobuf-gradle-plugin插件,他是用来从proto文件自动生成java代码的: //Project的build.gradle中添加rotobuf-gradle-plugin插

  • Android 解决WebView无法上传文件的问题

    Android 解决WebView无法上传文件的问题 Android原生的WebView并不支持上传文件,需要我们自己实现相应的方法.于是我把工作中的相关代码记录下来.下次直接拿来用就行了.一点一滴都是经验. 1.需要定义三个变量 private ValueCallback<Uri[]> uploadMessageAboveL; private final static int FILE_CHOOSER_RESULT_CODE = 10000; private ValueCallback<

  • Android动画之小球拟合动画实例

    Android动画之小球拟合动画实例 实现效果: 动画组成: 1.通过三阶贝塞尔曲线来拟合圆,拟合系数的由来,以及怎么选控制点. 2.利用画布canvas.translate,以及scale,rotate的方法,来渐变绘制的过程. 3.熟悉拟合过程. 4.不熟悉的话,先绘制辅助点的移动路线,对理解两个圆的分裂的拟合过程有好处. package com.example.administrator.animationworkdemo.views; import android.animation.V

  • 详解Android ViewCompat的作用

    详解Android ViewCompat的作用 ViewCompat类主要是用来提供兼容性的, 比如我最近看的比较的多的canScrollVertically方法, 在ViewCompat里面针对几个版本有不同的实现, 原理上还是根据版本判断, 有时甚至还要判断传入参数的类型. 但是要注意的是, ViewCompat仅仅让你调用不崩溃, 并不保证你调用的结果在不同版本的机器上一致. 关于如何优雅的组织代码, ViewCompat类的结构非常适合我们参考. ViewCompat里面定义了一个接口,

  • Android绘制验证码的实例代码

    在前面仿华为加载动画.仿网易音乐听歌识曲-麦克风动画中,我们通过绘图的基础知识完成了简单的绘制.在本例中,我们将绘制常见的验证码. 一.效果图 二.知识点与思路分析 通过上面的效果图观察,我们可以看到里面有绘制的随机线条,随机绘制的验证码. 绘制线条,直线或曲线 绘制文本,生成的验证码文本的绘制 绘制圆点. 三.代码编写 /** * Created by Iflytek_dsw on 2017/7/3. */ public class IdentifyCodeUtil { private sta

  • Android中应用前后台切换监听的实现详解

    前言 最近在工作中遇到了这么一个需求:如何实现 Android 应用前后台切换的监听?下面来一起看看详细的介绍: iOS 内边是可以实现的,AppDelegate 给了一个回调监听: @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { func applicationWillResignActive(_ application: UIApplication) { // Sent when the a

  • Android 滑动监听的实例详解

    Android 滑动监听的实例详解 摘要: ScollBy,ScollTo是对内容的移动,view.ScollyBy是对view的内容的移动 view,ScollTo是对内容的移动(移动到指定位置),view.ScollyBy是对view的内容的移动(移动距离) 在次activity中,当手指点击TextView ,此时是ViewGroup 响应还是TextView响应呢? 代码实践: 在activity中重写onTouchEvent(): public boolean onTouchEvent

  • Android TextWatcher内容监听死循环案例详解

    Android TextWatcher内容监听死循环 TextWatcher如何避免在afterTextChanged中调用setText后导致死循环,今天在用TextView时,添加了addTextChangedListener方法监听内容改变,在afterTextChanged方法中又执行了setText方法,结果造成afterTextChanged方法再次调用,然后setText,因此造成了死循环的问题.列出此问题,以备后忘. 先贴Google文档原文说明: /** * This meth

  • Android 中倒计时验证两种常用方式实例详解

    Android 中倒计时验证两种常用方式实例详解 短信验证码功能,这里总结了两种常用的方式,可以直接拿来使用.看图: 说明:这里的及时从10开始,是为了演示的时间不要等太长而修改的. 1.第一种方式:Timer /** * Description:自定义Timer * <p> * Created by Mjj on 2016/12/4. */ public class TimeCount extends CountDownTimer { private Button button; //参数依

  • 在Android中使用WebSocket实现消息通信的方法详解

    前言 消息推送功能可以说移动APP不可缺少的功能之一,一般简单的推送我们可以使用第三方推送的SDK,比如极光推送.信鸽推送等,但是对于消息聊天这种及时性有要求的或者三方推送不满足业务需求的,我们就需要使用WebSocket实现消息推送功能. 基本流程 WebSocket是什么,这里就不做介绍了,我们这里使用的开源框架是https://github.com/TakahikoKawasaki/nv-websocket-client 基于开源协议我们封装实现WebSocket的连接.注册.心跳.消息分

  • Vue之监听方法案例详解

    vue中的监听方法 watch 注意 名字 你想监听哪个属性,就要和他起一样的名字 1.作用 用来监听vue实例中的数据变化 可以随时修改状态的变化 2.触发条件 当你监听的属性发生变化时,会自动调用对应的监听方法 3.使用场景 用于异步处理,开销比较大的运算 4.示例 watch:{ name(newvalue,oldvalue){ //计算属性可以接受两个参数,第一个参数是新的属性值,第二参数是老的属性值 // this.age // console.log('name属性发生变化了') c

  • Spring事件监听机制观察者模式详解

    目录 前言 观察者模式 观察者的角色定义 Java中的事件机制 Spring中的事件机制 Spring事件监听案例 小结 前言 Spring中提供了一套默认的事件监听机制,在容器初始化时便使用了这套机制.同时,Spring也提供了事件监听机制的接口扩展能力,开发者基于此可快速实现自定义的事件监听功能. Spring的事件监听机制是在JDK事件监听的基础上进行的扩展,也是在典型观察者模式上的进一步抽象和改进.所以,结合Spring的事件监听机制与观察者模式来学习,可以达到理论与实践的完美融合. 本

  • Android中gson、jsonobject解析JSON的方法详解

    JSON的定义: 一种轻量级的数据交换格式,具有良好的可读和便于快速编写的特性.业内主流技术为其提供了完整的解决方案(有点类似于正则表达式 ,获得了当今大部分语言的支持),从而可以在不同平台间进行数据交换.JSON采用兼容性很高的文本格式,同时也具备类似于C语言体系的行为. JSON对象: JSON中对象(Object)以"{"开始, 以"}"结束. 对象中的每一个item都是一个key-value对, 表现为"key:value"的形式, ke

  • Android中屏幕密度和图片大小的关系详解

    Android中屏幕密度和图片大小的关系详解 前言 Android中支持许多资源,包括图片(Bitmap),对应于bitmap的文件夹是drawable,除了drawable,还有drawable-ldpi.drawable-mdpi.drawable-hdpi.drawable-xhdpi.drawable-xxhdpi等,同一张图片放到上面不同的文件夹中是有区别的,比如一张100 * 100像素大小的图片,分别放在上述各个文件夹中,然后将其设置为ImageView(假设宽高都是wrap_co

  • vue1.0和vue2.0的watch监听事件写法详解

    如下所示: watch: { aaa: { handler: function (newVal,oldVal) { console.log('当前的值:'+ newVal); console.log('旧的值' + oldVal); }, deep: true //深度监听 } } 以上这篇vue1.0和vue2.0的watch监听事件写法详解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们.

随机推荐