在 Android 开发过程中,我们有时候需要获取当前的 Activity 实例,比如弹出 Dialog 的操作,AlertDialog 的创建必须用到 Activity 的 Window 。
反射是我们经常会想到的方法,思路大概为
- 获取 ActivityThread 重点内容 中所有的ActivityRecord
- 从 ActivityThread 中获取所有状态不是 pause 的实例
一个使用反射来实现的代码大概如下
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;
}
然而这种方式的缺点和所有使用反射解决问题的缺点一样
- 反射通常会比较慢 (其实还是可以接受的)
- 不稳定性,这是主要的原因,你不能保证 Andorid框架的代码在未来不变化,如果未来 某些字段 名、方法名被改变了呢,所以采用反射的方式并不是完全可靠的
既然反射不是很可靠的,那么有一种比较可靠的方式,就是将所有的 Activity 都继承自我们的实现的基类,在基类中对 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即其以上。不过还在现在大多数设备都满足了这个要求。
public class MyActivityManager {
private static MyActivityManager sInstance = new MyActivityManager();
// 采用弱引用持有 Activity ,避免造成 内存泄露
private WeakReference 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);
}
}
本文章装载自 http://droidyue.com/blog/2016/02/21/thinking-of-getting-the-current-activity-in-android/