Android开发中关于获取当前Activity的一些思考

在Android开发过程中,我们有时候需要获取当前的Activity实例,比如弹出Dialog操作,必须要用到这个。关于如何实现由很多种思路,这其中有的简单,有的复杂,这里简单总结一下个人的一些经验吧。

反射

反射是我们经常会想到的方法,思路大概为

  • 获取ActivityThread中所有的ActivityRecord
  • 从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固定不变。所以可靠性不是完全可靠。

Activity基类

既然反射不是很可靠,那么有一种比较可靠的方式,就是使用Activity基类。

在Activity的onResume方法中,将当前的Activity实例保存到一个变量中。

public class BaseActivity extends Activity{

  @Override
  protected void onResume() {
    super.onResume();
    MyActivityManager.getInstance().setCurrentActivity(this);
  }
}

然而,这一种方法也不仅完美,因为这种方法是基于约定的,所以必须每个Activity都继承BaseActivity,如果一旦出现没有继承BaseActivity的就可能有问题。

回调方法

介绍了上面两种不是尽善尽美的方法,这里实际上还是有一种更便捷的方法,那就是通过Framework提供的回调来实现。

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

So,一个简单的实现如下

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) {

      }
    });
  }
}

然而,金无足赤人无完人,这种方法唯一的遗憾就是只支持API 14即其以上。不过还在现在大多数设备都满足了这个要求。

为什么是弱引用

可能有人会带着疑问看到这里,MyActivityManager是个什么鬼,好,我们现在看一下这个类的实现

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的设置和获取。

那么为什么要使用弱引用持有Activity实例呢?

其实最主要的目的就是避免内存泄露,因为使用默认的强引用会导致Activity实例无法释放,导致内存泄露的出现。

以上就是本文的全部内容,希望对大家学习Android软件编程有所帮助。

(0)

相关推荐

  • Android实现在子线程中更新Activity中UI的方法

    本文实例讲述了Android实现在子线程中更新Activity中UI的方法.分享给大家供大家参考,具体如下: 在Android平台下,进行多线程编程时,经常需要在主线程之外的一个单独的线程中进行某些处理,然后更新用户界面显示.但是,在主线线程之外的线程中直接更新页面显示的问题是:系统会报这个异常: ERROR/AndroidRuntime(1222): android.view.ViewRoot$CalledFromWrongThreadException: Only the original

  • Android:“万能”Activity重构篇

    前言 写Android:如何编写"万能"的Activity的这篇文章到现在已经好久了,但是由于最近事情较多,写重构篇的计划就一直被无情的耽搁下来了,借这几天还算有点空余时间,把自己这桩心事了解下. 其实大家也知道Android:如何编写"万能"的Activity的这篇文章只是个引子,其实我真正想引出的是mvp设计模式,因为最近自己最近在用mvp做项目,自己对mvp有一些感悟,因此我将用mvp进行"万能"activity的重构. 同时也有一些朋友与

  • 详解Android开发中Activity的四种launchMode

    Activity栈主要用于管理Activity的切换.当使用Intent跳转至某个目标Activity,需要根据目标Activity的加载模式来加载. Activity一共有以下四种launchMode: 1.standard:默认,每次使用Intent跳转到目标Activity时都创建一个新的实例.坏处是每次进入都要创建新的实例,执行OnCreate方法. 2.singleTop:如果要跳转的目标Activity正好在task的顶部(说明当前肯定不在目标task里,例如我在微信首页,然后想使用

  • Android:如何编写“万能”的Activity

    前言 自己android开发也有些年头了,每每回想起作为初学者的时候自己写的代码,自己会有种喷自己的冲动,代码写的太渣了.因此想着自己要总结下以前代码中的不合理的地方,希望能给初学者一些帮助.我希望这是一个系列的文章. 本节内容 一个"万能"的Activity是什么样子,"万能"的Activity有哪些不好的地方 开始编写"万能"的Activity 作为了一个初学者,有可能会有好多的朋友把Activity写的很"万能",当然没

  • Android开发中Activity创建跳转及传值的方法

    在Android系统的江湖中有四大组件:活动(Activity), 服务(Service), 广播接收器(Broadcast Reciver)和内容提供者(Content Provider). 今天所介绍的就是Android开发中的四大组件之一:Activity,其他那三大组件以后再进行介绍.说道Android中的Activity,如果你做过iOS开发的话,Activity类似于iOS中的ViewController(视图控制器).在应用中能看到的东西都是放在活动中的.活动是安卓开发比较重要的东

  • Android编程中activity启动时出现白屏、黑屏问题的解决方法

    本文实例讲述了Android编程中activity启动时出现白屏.黑屏问题的解决方法.分享给大家供大家参考,具体如下: 默认情况下 activity 启动的时候先把屏幕刷成白色,再绘制界面,绘制界面或多或少有点延迟,这段时间中你看到的就是白屏,显然影响用户体验,怎么消除呢? 在 Activity theme 设置style 即可 <style name="AppTheme" parent="android:Theme.Light.NoTitleBar">

  • Android判断Activity是否在最上层的方法

    本文实例讲述了Android判断Activity是否在最上层的方法.分享给大家供大家参考,具体如下: private boolean isTopActivity(Activity activity) { ActivityManager am = (ActivityManager)getSystemService(ACTIVITY_SERVICE); ComponentName cn = am.getRunningTasks(1).get(0).topActivity; return cn.get

  • Android activity堆栈及管理实例详解

    本示例演示如何通过设置Intent对象的标记,来改变当前任务堆栈中既存的Activity的顺序. 1. Intent对象的Activity启动标记说明: FLAG_ACTIVITY_BROUGHT_TO_FRONT 应用程序代码中通常不设置这个标记,而是由系统给单任务启动模式的Activity的设置. FLAG_ACTIVITY_CLEAR_TASK 如果给Intent对象添加了这个标记,那么在Activity被启动之前,会导致跟这个Activity关联的任何既存的任务都被清除.也就是说新的Ac

  • Android实现Activity水平和垂直滚动条的方法

    本文实例讲述了Android实现Activity水平和垂直滚动条的方法.分享给大家供大家参考,具体如下: <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:scrollbars="

  • Android中fragment与activity之间的交互(两种实现方式)

    (未给Fragment的布局设置BackGound) 之前关于Android中Fragment的概念以及创建方式,我专门写了一篇博文<详解Android中Fragment的两种创建方式>,就如何创建Fragment混合布局做了详细的分析,今天就来详细说道说道Fragment与宿主Activity之间是如何实现数据交互的. 我们可以这样理解,宿主Activity中的Fragment之间要实现信息交互,就必须通过宿主Activity,Fragment之间是不可能直接实现信息交互的. Fragmen

随机推荐