獲取棧頂 TopActivity 方法匯總

最近項(xiàng)目中遇到一個(gè)問題,需要做一個(gè)全局的彈窗,為此需要拿到當(dāng)前棧頂?shù)?Activity。在這里做一個(gè)總結(jié):

  1. ActivityManager.getRunningTasks()
    這個(gè)函數(shù)是官方的 public API,但已經(jīng)廢棄,原因是:“可能造成隱私泄露”。但因?yàn)榧嫒菪栽?,它仍然?huì)返回一小部分不敏感的數(shù)據(jù),比如當(dāng)前進(jìn)程的 Activities 或者 Launcher。
    換句話說,在 Android L 以上,返回結(jié)果非常不可靠,而且只能拿到ComponentName 而不是 Activity 實(shí)例,不建議使用。
public static ComponentName getTopActivity(Context c) {
        ActivityManager am = (ActivityManager) c
                .getSystemService(Context.ACTIVITY_SERVICE);
        if (am != null) {
            List<ActivityManager.RunningTaskInfo> infos
                    = am.getRunningTasks(1);
            if (infos != null && infos.size() != 0) {
                return infos.get(0).topActivity;
            }
        }
        return null;
    }
  1. BaseActivity 記錄生命周期回調(diào)
    這個(gè)方法對于沒有繼承 BaseActivity 的 Activity 是無效的……由此可見在項(xiàng)目開始時(shí)創(chuàng)建基類成員并寫進(jìn)開發(fā)規(guī)范多么重要……

    public abstract class BaseActivity extends AppCompatActivity {
        private static WeakReference<BaseActivity> 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
    這個(gè)方法可以在 Application 的 onCreate 函數(shù)中注冊
        private static WeakReference<Activity> 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
    這個(gè)方法是實(shí)際我使用的,因?yàn)轫?xiàng)目是 Xposed 模塊,可能是本機(jī)代碼優(yōu)化的原因,Application.onCreate() 函數(shù) hook 不到,就算 hook 到了注冊成功也收不到回調(diào),有點(diǎn)莫名其妙。如果看過 ActivityThread 的源碼,會(huì)發(fā)現(xiàn)里面有一個(gè)內(nèi)部類 ActivityClientRecord,這個(gè)類是用來保存本進(jìn)程所有 Activity 實(shí)例及生命狀態(tài)的。缺點(diǎn)是:由于使用了反射和內(nèi)部類,兼容性無法保證,如果 ROM 廠商改個(gè)名字可能就跪了。而且 Android 9 以上限制了反射的使用,需要進(jìn)行一下適配。
        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<Object, Object> mActivities = (Map<Object, Object>)
                        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/

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容