获取栈顶 TopActivity 方法汇总

最近项目中遇到一个问题,需要做一个全局的弹窗,为此需要拿到当前栈顶的 Activity。在这里做一个总结:

  1. ActivityManager.getRunningTasks()
    这个函数是官方的 public API,但已经废弃,原因是:“可能造成隐私泄露”。但因为兼容性原因,它仍然会返回一小部分不敏感的数据,比如当前进程的 Activities 或者 Launcher。
    换句话说,在 Android L 以上,返回结果非常不可靠,而且只能拿到ComponentName 而不是 Activity 实例,不建议使用。
public static ComponentName getTopActivity(Context c) {
        ActivityManager am = (ActivityManager) c
                .getSystemService(Context.ACTIVITY_SERVICE);
        if (am != null) {
            List infos
                    = am.getRunningTasks(1);
            if (infos != null && infos.size() != 0) {
                return infos.get(0).topActivity;
            }
        }
        return null;
    }
  1. BaseActivity 记录生命周期回调
    这个方法对于没有继承 BaseActivity 的 Activity 是无效的……由此可见在项目开始时创建基类成员并写进开发规范多么重要……

    public abstract class BaseActivity extends AppCompatActivity {
        private static WeakReference sTopActivity;

        public static BaseActivity getTopActivity() {
            return sTopActivity == null ? null : sTopActivity.get();
        }

        @Override
        protected void onStart() {
            super.onStart();
            sTopActivity = new WeakReference<>(this);
        }

        @Override
        protected void onStop() {
            super.onStop();
            if (getTopActivity() == this) {
                sTopActivity = null;
            }
        }
    }
  1. Application.registerActivityLifecycleCallback
    这个方法可以在 Application 的 onCreate 函数中注册
        private static WeakReference sTopActivity;

        public static Activity getTopActivity() {
            return sTopActivity == null ? null : sTopActivity.get();
        }

        @Override
        public void onCreate() {
            super.onCreate();

            registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
                @Override
                public void onActivityCreated(Activity activity, Bundle savedInstanceState) {

                }

                @Override
                public void onActivityStarted(Activity activity) {
                    sTopActivity = new WeakReference<>(activity);
                }

                @Override
                public void onActivityResumed(Activity activity) {

                }

                @Override
                public void onActivityPaused(Activity activity) {

                }

                @Override
                public void onActivityStopped(Activity activity) {
                    if (activity == getTopActivity()) {
                        sTopActivity = null;
                    }
                }

                @Override
                public void onActivitySaveInstanceState(Activity activity, Bundle outState) {

                }

                @Override
                public void onActivityDestroyed(Activity activity) {

                }
            });
        }
  1. ActivityThread.ActivityClientRecord
    这个方法是实际我使用的,因为项目是 Xposed 模块,可能是本机代码优化的原因,Application.onCreate() 函数 hook 不到,就算 hook 到了注册成功也收不到回调,有点莫名其妙。如果看过 ActivityThread 的源码,会发现里面有一个内部类 ActivityClientRecord,这个类是用来保存本进程所有 Activity 实例及生命状态的。缺点是:由于使用了反射和内部类,兼容性无法保证,如果 ROM 厂商改个名字可能就跪了。而且 Android 9 以上限制了反射的使用,需要进行一下适配。
        private boolean mIgnore = false;
        private Field mActivityField;
        private Field mActivitiesField;
        private Field mStoppedField;

        @SuppressWarnings("unchecked")
        private Activity getTopActivity() {
            if (mIgnore) {
                return null;
            }
            try {
                if (mActivitiesField == null) {
                    mActivitiesField = ReflectUtils.getDeclaredField(
                            ActivityThread.class, "mActivities"
                    );
                    Class cls = Class.forName("android.app.ActivityThread$ActivityClientRecord");
                    mActivityField = ReflectUtils.getDeclaredField(cls, "activity");
                    mStoppedField = ReflectUtils.getDeclaredField(cls, "stopped");
                }

                ActivityThread thread = ActivityThread.currentActivityThread();
                final Map mActivities = (Map)
                        mActivitiesField.get(thread);

                for (Object r : mActivities.values()) {
                    Activity activity = (Activity) mActivityField.get(r);
                    if (activity.isFinishing() || activity.isDestroyed()
                        || ((boolean) mStoppedField.get(r))) {
                        continue;
                    }
                    return activity;
                }
            } catch (Exception e) {
                mIgnore = true;
                Log.e(TAG, "getTopActivity: ", e);
            }
            return null;
        }

下面是 ReflectUtils

public static Field getDeclaredField(Class cls, String name) {
        Field field;
        try {
            field = cls.getDeclaredField(name);
            field.setAccessible(true);
        } catch (NoSuchFieldException e) {
            field = null;
            Log.e(TAG, "getDeclaredField: " + name, e);
        }
        return field;
    }

对于 Android9 以上,可以参考
http://weishu.me/2019/03/16/another-free-reflection-above-android-p/

你可能感兴趣的:(获取栈顶 TopActivity 方法汇总)