Android进阶——借助简单便捷的ActivityLifecycleCallbacks实现全周期监听Activity

本文介绍如何利用Application.ActivityLifecycleCallbacks接口优雅地监控Activity的生命周期,避免代码冗余,提高开发效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

引言

在开发中由于业务的需求,我们需要在Activity对应的生命周期方法中去完成对应的工作,比如说需要在Activity的onResume中注册某个SDK或者广播接收器、抑或是尝试打开Camera、判断app 是否在后台运行除了令人蛋疼的判断当前runningProcess 或者runningTasks 方法等,然后在Activity的onPause()中及时注销或释放掉,以前也许会在每个Activity对应的方法中增加对应的代码即可,但是从一定意义上说这代码是冗余的且不优雅,从Android4.0之后添加了Application.ActivityLifecycleCallbacks接口,我们开发者就有了一种更优雅的方案。

一、Application.ActivityLifecycleCallbacksgais概述

记得我第一次知道这个接口之后,第一时间跑到官网中查询文档,结果发现Google 又偷懒了,Summary部分竟然一句话都没有关于它的描述,差点怀疑是否进错了网站,ORZ,才发现其实是这个接口太简单了背后的原理也十分简单,本来我还以为会是观察者模式,后面发现就是一个普通回调。但是借助它我可以优雅地监控Activity的生命周期——一经注册,就会自动监听整个APP 中所有Activity 的生命周期方法的执行(会在对应的父类Activity的方法被执行之后自动触发)

二、Application.ActivityLifecycleCallbacks源码急背后的原理简要描述

Application.ActivityLifecycleCallbacks是Application中的一个接口,使用起来也很简单,只需要调用registerActivityLifecycleCallbacks方法即可完成注册(通常是在Application中完成的)。


public class Application extends ContextWrapper implements ComponentCallbacks2 {
    private ArrayList<ComponentCallbacks> mComponentCallbacks =
            new ArrayList<ComponentCallbacks>();
    private ArrayList<ActivityLifecycleCallbacks> mActivityLifecycleCallbacks =
            new ArrayList<ActivityLifecycleCallbacks>();
    private ArrayList<OnProvideAssistDataListener> mAssistCallbacks = null;

    /** @hide */
    public LoadedApk mLoadedApk;

    public interface ActivityLifecycleCallbacks {
        void onActivityCreated(Activity activity, Bundle savedInstanceState);
        void onActivityStarted(Activity activity);
        void onActivityResumed(Activity activity);
        void onActivityPaused(Activity activity);
        void onActivityStopped(Activity activity);
        void onActivitySaveInstanceState(Activity activity, Bundle outState);
        void onActivityDestroyed(Activity activity);
    }

    public Application() {
        super(null);
    }

    @CallSuper
    public void onCreate() {
    }

    /**
     * This method is for use in emulated process environments.  It will
     * never be called on a production Android device, where processes are
     * removed by simply killing them; no user code (including this callback)
     * is executed when doing so.
     */
    @CallSuper
    public void onTerminate() {
    }

    @CallSuper
    public void onConfigurationChanged(Configuration newConfig) {
        Object[] callbacks = collectComponentCallbacks();
        if (callbacks != null) {
            for (int i=0; i<callbacks.length; i++) {
                ((ComponentCallbacks)callbacks[i]).onConfigurationChanged(newConfig);
            }
        }
    }

    @CallSuper
    public void onLowMemory() {
        Object[] callbacks = collectComponentCallbacks();
        if (callbacks != null) {
            for (int i=0; i<callbacks.length; i++) {
                ((ComponentCallbacks)callbacks[i]).onLowMemory();
            }
        }
    }

    @CallSuper
    public void onTrimMemory(int level) {
        Object[] callbacks = collectComponentCallbacks();
        if (callbacks != null) {
            for (int i=0; i<callbacks.length; i++) {
                Object c = callbacks[i];
                if (c instanceof ComponentCallbacks2) {
                    ((ComponentCallbacks2)c).onTrimMemory(level);
                }
            }
        }
    }
    /*
    **注册ActivityLifecycleCallbacks回调
    */
    public void registerActivityLifecycleCallbacks(ActivityLifecycleCallbacks callback) {
        synchronized (mActivityLifecycleCallbacks) {
            mActivityLifecycleCallbacks.add(callback);
        }
    }

    public void unregisterActivityLifecycleCallbacks(ActivityLifecycleCallbacks callback) {
        synchronized (mActivityLifecycleCallbacks) {
            mActivityLifecycleCallbacks.remove(callback);
        }
    }


    // ------------------ Internal API ------------------
    /* package */ void dispatchActivityCreated(Activity activity, Bundle savedInstanceState) {
        Object[] callbacks = collectActivityLifecycleCallbacks();
        if (callbacks != null) {
            for (int i=0; i<callbacks.length; i++) {
                ((ActivityLifecycleCallbacks)callbacks[i]).onActivityCreated(activity,
                        savedInstanceState);
            }
        }
    }

    /* package */ void dispatchActivityStarted(Activity activity) {
        Object[] callbacks = collectActivityLifecycleCallbacks();
        if (callbacks != null) {
            for (int i=0; i<callbacks.length; i++) {
                ((ActivityLifecycleCallbacks)callbacks[i]).onActivityStarted(activity);
            }
        }
    }

    /* package */ void dispatchActivityResumed(Activity activity) {
        Object[] callbacks = collectActivityLifecycleCallbacks();
        if (callbacks != null) {
            for (int i=0; i<callbacks.length; i++) {
                ((ActivityLifecycleCallbacks)callbacks[i]).onActivityResumed(activity);
            }
        }
    }

    /* package */ void dispatchActivityPaused(Activity activity) {
        Object[] callbacks = collectActivityLifecycleCallbacks();
        if (callbacks != null) {
            for (int i=0; i<callbacks.length; i++) {
                ((ActivityLifecycleCallbacks)callbacks[i]).onActivityPaused(activity);
            }
        }
    }

    /* package */ void dispatchActivityStopped(Activity activity) {
        Object[] callbacks = collectActivityLifecycleCallbacks();
        if (callbacks != null) {
            for (int i=0; i<callbacks.length; i++) {
                ((ActivityLifecycleCallbacks)callbacks[i]).onActivityStopped(activity);
            }
        }
    }

    /* package */ void dispatchActivitySaveInstanceState(Activity activity, Bundle outState) {
        Object[] callbacks = collectActivityLifecycleCallbacks();
        if (callbacks != null) {
            for (int i=0; i<callbacks.length; i++) {
                ((ActivityLifecycleCallbacks)callbacks[i]).onActivitySaveInstanceState(activity,
                        outState);
            }
        }
    }

    /* package */ void dispatchActivityDestroyed(Activity activity) {
        Object[] callbacks = collectActivityLifecycleCallbacks();
        if (callbacks != null) {
            for (int i=0; i<callbacks.length; i++) {
                ((ActivityLifecycleCallbacks)callbacks[i]).onActivityDestroyed(activity);
            }
        }
    }
    ...
}

然后在Activity的对应的生命周期方法的内部,通过Application来调用对应的dispatchActivityXxxxx方法,从而实现全生命周期的监听

public class Activity extends ContextThemeWrapper implements LayoutInflater.Factory2,Window.Callback, KeyEvent.Callback,
        OnCreateContextMenuListener, ComponentCallbacks2,
        Window.OnWindowDismissedCallback, WindowControllerCallback {
        ...
        @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);
            }
        }
        if (savedInstanceState != null) {
            Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
            mFragments.restoreAllState(p, mLastNonConfigurationInstances != null
                    ? mLastNonConfigurationInstances.fragments : null);
        }
        mFragments.dispatchCreate();
        getApplication().dispatchActivityCreated(this, savedInstanceState);
        if (mVoiceInteractor != null) {
            mVoiceInteractor.attachActivity(this);
        }
        mCalled = true;
    }

    @CallSuper
    protected void onStart() {
        if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStart " + this);
        mCalled = true;

        mFragments.doLoaderStart();

        getApplication().dispatchActivityStarted(this);
    }
    ...
    }

三、ActivityLifecycleCallbacks的应用

Application.ActivityLifecycleCallbacks中对应的监听的生命周期方法会在Activity中的生命方法调用父类的方法之后被触发,由源码也可得知。

  • 继承Application重写onCreate等方法
  • 调用registerActivityLifecycleCallbacks方法注册ActivityLifecycleCallbacks
package com.crazyview.activitylifecycle;

import android.app.Activity;
import android.app.Application;
import android.os.Bundle;
import android.util.Log;

/**
 * Created by cmo on 2017/12/23.
 */

public class LifecycleApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        init();
    }

    private void init() {
        registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
            @Override
            public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
                Log.e("Lifecycle",activity.getLocalClassName()+" was Created"+"activity==null   "
                        +(activity==null)+"     activity.isFinishing()  "+(activity.isFinishing())+"    activity.isDestroyed()  "+activity.isDestroyed());
            }

            @Override
            public void onActivityStarted(Activity activity) {
                Log.e("Lifecycle",activity.getLocalClassName()+" was Started"+"activity==null   "
                            +(activity==null)+"     activity.isFinishing()   "+(activity.isFinishing())+"   activity.isDestroyed()  "+activity.isDestroyed());
            }

            @Override
            public void onActivityResumed(Activity activity) {
                 Log.e("Lifecycle",activity.getLocalClassName()+" was oResumed"+"activity==null   "
                        +(activity==null)+"activity.isFinishing()   "+(activity.isFinishing())+"activity.isDestroyed() "+activity.isDestroyed());
            }

            @Override
            public void onActivityPaused(Activity activity) {
                Log.e("Lifecycle",activity.getLocalClassName()+" was Pauseed"+"activity==null   "
                        +(activity==null)+"activity.isFinishing()   "+(activity.isFinishing())+"activity.isDestroyed()  "+activity.isDestroyed());
            }

            @Override
            public void onActivityStopped(Activity activity) {
                Log.e("Lifecycle",activity.getLocalClassName()+" was Stoped"+"activity==null    "
                        +(activity==null)+"activity.isFinishing()   "+(activity.isFinishing())+"activity.isDestroyed() "+activity.isDestroyed());
            }

            @Override
            public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
                Log.e("Lifecycle",activity.getLocalClassName()+" was SaveInstanceState"+"activity==null "
                        +(activity==null)+"activity.isFinishing()   "+(activity.isFinishing())+"activity.isDestroyed()  "+activity.isDestroyed());
            }

            @Override
            public void onActivityDestroyed(Activity activity) {
                Log.e("Lifecycle",activity.getLocalClassName()+" was Destroyed"+"activity==null"
                        +(activity==null)+"  activity.isFinishing()  "+(activity.isFinishing())+"  activity.isDestroyed()"+activity.isDestroyed());
            }
        });
    }
}
  • 在清单中声明Application,无需在Activity添加额外的代码就可以实现监控
package com.crazyview.activitylifecycle;

import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;

public class MainActivity extends AppCompatActivity {

    public static final String LIFECYCLE = "MainActivity:Lifecycle";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Log.e(LIFECYCLE, "onCreate() is Running__before super.onCreate called");
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.e(LIFECYCLE, "onCreate() is Running__after super.onCreate called");
    }

    @Override
    protected void onRestart() {
        Log.e(LIFECYCLE, "onRestart() is Running__before super's called");
        super.onRestart();
        Log.e(LIFECYCLE, "onRestart() is Running__after super's called");
    }

    @Override
    protected void onStart() {
        Log.e(LIFECYCLE, "onStart() is Running__before super.onStart called");
        super.onStart();
        Log.e(LIFECYCLE, "onStart() is Running__after super.onStart called");
    }

    @Override
    protected void onResume() {
        Log.e(LIFECYCLE, "onResume() is Running__before super.onResume called");
        super.onResume();
        Log.e(LIFECYCLE, "onResume() is Running__after super.onResume called");
    }

    @Override
    protected void onPause() {
        Log.e(LIFECYCLE, "onPause() is Running__before super's called");
        super.onPause();
        Log.e(LIFECYCLE, "onPause() is Running__after super's called");
    }

    @Override
    protected void onStop() {
        Log.e(LIFECYCLE, "onStop() is Running__before super's called");
        super.onStop();
        Log.e(LIFECYCLE, "onStop() is Running__after super's called");
    }

    @Override
    protected void onDestroy() {
        Log.e(LIFECYCLE, "onDestroy() is Running__before super's called");
        super.onDestroy();
        Log.e(LIFECYCLE, "onDestroy() is Running__after super's called");
    }

    public void toTask(View view) {
        startActivity(new Intent(this, TaskActivity.class));
        //finish();
    }
}

打开MainActivity时候的运行结果:
这里写图片描述
finish当前Activity时:
这里写图片描述

PS:一些有用的adb命令

1、通过adb 命令获取当前运行的Activity

adb shell dumpsys activity | findstr "mFocusedActivity"

2、通过adb 使用命令行截取对应的log并保存到硬盘对应目录下

adb logcat -s tag >d:log.txt

3、将log和当前时间 保存到当前目录下

adb logcat -v time >a.log

4、通过android.app.ActivityManager获取topActivity

 public static String getTopActivity(Context context) {
        android.app.ActivityManager am = (android.app.ActivityManager) context.getSystemService(ACTIVITY_SERVICE);
        ComponentName cn = am.getRunningTasks(1).get(0).topActivity;
        return cn.getShortClassName().toString();
    }
### 阶段二:初窥门径 —— 构建简单 App 在这个阶段,你需要深入了解 Android 应用的基本结构及其工作原理。以下是针对此阶段的一些详细内容和建议题目的解析。 #### 1. **创建第一个“Hello World”应用程序** 这是一个非常经典的入门示例,让你初步认识如何配置项目、编写代码以及运行结果。 **题目**: 实现一个包含文本框 (`EditText`) 和按钮 (`Button`) 的页面,在按下按钮后将文本框的内容显示在一个新的弹窗上。 ```kotlin // MainActivity.kt import android.os.Bundle import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity import kotlinx.android.synthetic.main.activity_main.* class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) button.setOnClickListener { val inputText = editText.text.toString() AlertDialog.Builder(this).apply { setMessage(inputText) setPositiveButton("确定", null) show() } } } } ``` #### 2. **XML 布局设计与资源管理** 理解 XML 文件是如何描述 UI 元素的排列方式,并学会使用 `@string`, `@drawable` 等引用方式来简化代码。 **题目**: 设计一个多标签页的应用程序主界面上有三个图标对应三种不同颜色的主题切换功能。 - 使用 `<selector>` 定义状态列表绘制器(State List Drawable)改变按钮背景色。 - 设置主题样式并通过代码动态更改Application Theme。 ```xml <!-- res/drawable/button_background.xml --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="true" android:color="@color/colorPrimaryDark"/> <item android:color="@color/colorAccent"/> </selector> <!-- styles.xml --> <style name="AppTheme.Red" parent="Theme.AppCompat.Light.DarkActionBar"> <!-- Customize your base theme here --> <item name="colorPrimary">@color/red</item> <item name="colorPrimaryDark">@color/dark_red</item> <item name="colorAccent">@color/light_red</item> </style> // Switch Themes in Code val nightModeFlags = context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK if (nightModeFlags == Configuration.UI_MODE_NIGHT_YES) { // Set dark theme style. } else { // Set light theme style. } ``` #### 3. **Activity 生命周期理解和事件处理** 掌握 Activity 的各个生命周期回调函数的作用范围及时机点;熟练运用 OnClickListener 监听点击事件和其他用户交互行为。 **题目**: 分析下面这个简单的日志记录程序,解释每个 Log.d 函数对应的时机是什么? ```java public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button btnClickMe = findViewById(R.id.btn_click_me); btnClickMe.setOnClickListener(new View.OnClickListener(){ @Override public void onClick(View v){ Log.d(TAG,"onClick called"); }}); } @Override protected void onStart(){super.onStart();Log.d(TAG,"onStart");} @Override protected void onResume(){super.onResume();Log.d(TAG,"onResume");} @Override protected void onPause(){super.onPause();Log.d(TAG,"onPause");} @Override protected void onStop (){super.onStop ();Log.d(TAG,"onStop ");} @Override protected void onDestroy(){super.onDestroy();Log.d(TAG,"onDestroy");} } ``` * 当首次启动应用时依次输出 `onCreate -> onStart -> onResume`. * 用户按返回键关闭当前 activity 后,则会顺序打印出 `onPause -> onStop -> onDestroy`. --- ### 阶段三:进阶提升 —— 深度挖掘框架细节 在掌握了基础之后,现在我们将进一步探索 Android 中更为复杂的特性和技术栈。 #### 1. **数据持久化方案** 除了常见的 SQLite 数据库外,还可以采用 Room Persistence Library 来简化 ORM 映射操作流程;另外 SharedPreferences 是一种轻量级存储方式适用于保存少量的关键值对信息。 **题目**: 如果想把用户的登录凭证加密保存起来该怎么办? 你可以结合 SharedPreference 和 Cipher 类完成加解密过程: ```kotlin fun encryptData(dataToEncrypt: String): ByteArray? { try { val cipher = Cipher.getInstance("AES/CBC/PKCS7Padding") val keySpec = SecretKeySpec(secretKey.toByteArray(), "AES") val ivParameterSpec = IvParameterSpec(ivByteArray) cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivParameterSpec) return cipher.doFinal(dataToEncrypt.toByteArray()) } catch (e: Exception){ e.printStackTrace()} return null } // Store Encrypted Data into Preferences prefs.edit().putString("ENCRYPTED_DATA_KEY", Base64.encodeToString(encryptedBytes)) ``` #### 2. **广播接收者(BroadcastReceiver)和服务(Service)** 了解系统级别的消息传递机制和服务进程之间通信的方式,尤其是 Foreground Services 提升了后台任务执行期间稳定性的同时也增加了安性。 **题目**: 如何保证音乐播放应用在锁屏状态下继续播放歌曲而不被打断? 通过设置 foreground service 将自身标记为前台服务即可防止被杀死: ```kotlin private fun startForegroundService(intent: Intent) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { startForegroundService(intent.apply{ putExtra(MediaSessionManager.IS_LOGGED_IN,true)}) notificationManager.notify(NOTIFICATION_ID,musicNotificationBuilder.build()) startForeground(NOTIFICATION_ID, musicNotificationBuilder.build()) } } ``` #### 3. **自定义视图与动画效果** 当你觉得默认提供的组件不再能满足个性化需求的时候就可以考虑动手创造属于自己的 Widget 或者添加炫酷转场特效吸引眼球啦~ **题目**: 自己手绘一个圆形进度条并且让它随时间逐渐填充完整。 利用 Canvas + Paint API 实现自定义 View 功能,配合 ValueAnimator 实现有节奏变化的效果: ```kotlin class CircleProgressView(context: Context?, attrs: AttributeSet?): View(context,attrs), Animator.AnimatorListener { init{...}// Initialize Properties override onDraw(canvas: Canvas){ canvas.drawArc(rectF,startAngle,sweepAngle,false,paint) } startAnimation(duration:Int=DEFAULT_DURATION){ animator.setDuration(duration).setTarget(sweepAngleValue).addListener(this) animator.start() } // Handle Animation Changes Here... override onAnimationUpdate(animation: ValueAnimator)=sweepAngle=(animation.animatedValue as Float)* MAX_SWEEP_ANGLE } ``` --- ### 阶段四:精通领域 —— 最佳实践与性能优化 到了这一层次你就已经是一名合格甚至优秀的 Android 开发人员了!接下来让我们一起来看看怎样才能做得更好吧! #### 1. **图像加载策略** 选用合适的图片缓存库如 Glide/Fresco/Picasso 能显著改善首帧渲染速度并减少流量消耗。 **题目**: 描述一下 Picasso 和 Glide 之间的差异在哪里? Picasso 更适合快速原型开发因为它足够简便直接; 而 Glide 支持更多的编码格式且内置了许多高级特性比如 gif 动图支持,磁盘 LRU Cache 管理等。 #### 2. **JSON 解析优化** 考虑到 GSON/Jackson 等三方序列化工具有着更好的灵活性和可读性,因此往往成为大型项目的首选。 **题目**: 性能上 Jackson 是否优于 Gson ? 一般来说 Jackson 因为其流式的解析模式比 Gson 整体吞吐率更高,尤其是在面对海量数据集的情况下优势明显。 #### 3. **内存泄漏检测工具 LeakCanary** 经常使用类似 LeakCanary 这样的开源诊断利器可以帮助开发者尽早发现潜在的风险点,从而避免不必要的 OOM 错误发生。 **题目**: 我该如何排查某个匿名内部类导致的对象泄露问题? 首先确保该内部类持有外部实例强引用的可能性最小化(例如静态变量),然后借助 LeakCanary 报告分析具体的堆栈追踪路径找到确切位置进行修复。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CrazyMo_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值