Android——如何优雅的维护最前台的Activity实例

Posted David-Kuper

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android——如何优雅的维护最前台的Activity实例相关的知识,希望对你有一定的参考价值。

android开发过程中,我们有时候需要获取当前的Activity实例,比如弹出Dialog操作、当Notification来到时判断某个页面是否在前台等等。所以维护一个当前显示的Activity是比较好的方式。关于如何实现由很多种思路,这其中有的简单,有的复杂,这里简单总结一下几种方式。

1、反射(获取ActivityThread,从而拿到当前的Activitys,该方式不推荐,比较消耗内存)
2、继承(通过基类控制每个继承类,从而维护一个当前Activity的引用,但无法控制不继承的类)
3、Application注册系统回调(通过framework层,在Application里面注册回调监听全局所有Activity运行状态,从而维护一个当前的Activity引用,推荐使用)


反射

我们可以像下面这样,通过反射来获取一个Activity的引用。
1. 获取ActivityThread中所有的ActivityRecord
2. 从ActivityRecord中获取状态不是pause的Activity并返回

一个使用反射来实现的代码大致如下:

public static Activity getActivity() 
    Class activityThreadClass = null;
    try 
        activityThreadClass = Class.forName("android.app.ActivityThread");
        Object activityThread = activityThreadClass.getMethod("currentActivityThread").invoke(null);
        Field activitiesField = activityThreadClass.getDeclaredField("mActivities");
        activitiesField.setAccessible(true);
        Map activities = (Map) activitiesField.get(activityThread);
        for (Object activityRecord : activities.values()) 
            Class activityRecordClass = activityRecord.getClass();
            Field pausedField = activityRecordClass.getDeclaredField("paused");
            pausedField.setAccessible(true);
            if (!pausedField.getBoolean(activityRecord)) 
                Field activityField = activityRecordClass.getDeclaredField("activity");
                activityField.setAccessible(true);
                Activity activity = (Activity) activityField.get(activityRecord);
                return activity;
            
        
     catch (ClassNotFoundException e) 
        e.printStackTrace();
     catch (NoSuchMethodException e) 
        e.printStackTrace();
     catch (IllegalAccessException e) 
        e.printStackTrace();
     catch (InvocationTargetException e) 
        e.printStackTrace();
     catch (NoSuchFieldException e) 
        e.printStackTrace();
    
    return null;

反射虽然是个利器,但是它也是把双刃剑:

  • 但是反射总是缓慢的,过多的反射、枚举会占用系统内存,拖慢系统速度。
  • 不稳定性,这个才是不推荐的原因,Android框架代码存在修改的可能性,谁要无法100%保证mActivities,paused固定不变。所以可靠性不是完全可靠。

继承

反射一般是不推荐的,java还可以通过继承的方式来实现这个维护。

  1. 建立一个Activity基类,在基类中维护一个全局的activity引用(currentActivity)
  2. 系统中的所有Activity继承自该Activity下,每当Activity中的onResume方法调用的时候就替换当前的currentActivity.
public class BaseActivity extends Activity

    @Override
    protected void onResume() 
        super.onResume();
        //这是一个管理当前Activity引用的工具类
        MyActivityManager.getInstance().setCurrentActivity(this);
    

这种方式对性能影响不大,而且非常简单,大部分的时候这种方式都能够解决问题。但是当我们的工程当中有了一些不继承自BaseActivity的类的时候(第三方的库下面的Activity),这个时候这种方式就不行了。因此,如果能够在系统层面做一个监听就好了,就是下面的回调方式。


回调

上面两种方式都不能满足我们的需求。第一种,反射虽好,用途强大,但是用在这里真的是杀鸡用牛刀;第二种,继承的方式,很好的使用了java的特性,但是对于不是继承自基类的类别就无法维护。还好,系统为我们提供了一个全局监控Activity生命周期的功能。

Android自 API 14开始引入了一个方法,即Application的registerActivityLifecycleCallbacks方法,用来监听所有Activity的生命周期回调,比如onActivityCreated,onActivityResumed等。

public class MyApplication extends Application 


    @Override
    public void onCreate() 
        super.onCreate();
        registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() 
            @Override
            public void onActivityCreated(Activity activity, Bundle savedInstanceState) 

            

            @Override
            public void onActivityStarted(Activity activity) 

            

            @Override
            public void onActivityResumed(Activity activity) 
                MyActivityManager.getInstance().setCurrentActivity(activity);
            

            @Override
            public void onActivityPaused(Activity activity) 

            

            @Override
            public void onActivityStopped(Activity activity) 

            

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

            

            @Override
            public void onActivityDestroyed(Activity activity) 

            
        );
    


/**
*

public class MyActivityManager 
    private static MyActivityManager sInstance = new MyActivityManager();
    private WeakReference<Activity> sCurrentActivityWeakRef;


    private MyActivityManager() 

    

    public static MyActivityManager getInstance() 
        return sInstance;
    

    public Activity getCurrentActivity() 
        Activity currentActivity = null;
        if (sCurrentActivityWeakRef != null) 
            currentActivity = sCurrentActivityWeakRef.get();
        
        return currentActivity;
    

    public void setCurrentActivity(Activity activity) 
        sCurrentActivityWeakRef = new WeakReference<Activity>(activity);
    


这里我们维护了一个指向当前展示的Activity的弱引用。使用弱引用的目的是为了不影响系统的回收,否则就会导致内存的泄漏。

以上是关于Android——如何优雅的维护最前台的Activity实例的主要内容,如果未能解决你的问题,请参考以下文章

android 2018 面试题

前台选择网站架构逻辑结构,如何实现?

如何优雅的处理 Android 重复点击 [建议收藏]

如何优雅的处理 Android 重复点击 [建议收藏]

如何优雅的维护 K8S Worker 节点

最优雅退出 Android 应用程序的 6 种方式