处理 "Activity has been destroyed" (java.lang.IllegalStateException) 异常?
Handling "Activity has been destroyed" (java.lang.IllegalStateException) exception?
我正在寻找一种通用方法来满足此异常。例如,如果用户保持非常快速地切换活动,这种情况总是会发生。因为显然有很多地方我们会尝试访问 activity 引用,当它为 null 时,应用程序会因此异常而崩溃。一种方法是每次访问 activity 引用时检查 "isFinishing()",我想知道是否有另一种更好和通用的方法来解决应用程序中的这个问题等级。
如果我的问题听起来很愚蠢或没有任何意义,请原谅我,但我想问没有坏处:)。
一切都与您如何为应用程序中的数据建模有关。 activity 实例数据只是临时数据,因此您应该查看以下备选方案,看看哪个更适合您的上下文:
您有会话级别的数据,这可以在单独的 class 中维护,可能是单例或在 Application 对象中。
如果您有需要持久保存的数据,请考虑 Android preferences 或数据库。
如果您希望在活动之间共享数据(不在应用程序级别),被调用者 Activity 应该 pass that via an intent.
从 OO 的角度考虑谁是该数据的合法所有者,或者是 activity 独有的临时数据(其他人无法访问)。
作为一般规则,Android 上下文应尽可能少地存储,并且仅在需要时使用。
如果您在尝试使用 Activity 上下文时遇到空异常或无效异常,这意味着您正在执行 Activity 的标准 Android 生命周期之外的操作。
由于生命周期的性质(异步),有时真的很难预测这些情况何时会出现……除非,您避免在生命周期事件之外执行操作上下文保证是活跃的。
例如:在异步任务甚至线程的 onPostExecute
方法中执行 Activity/Context 操作是一个定时炸弹。
作为一般规则,在尝试在生命周期方法(例如 onResume)之外使用 Activity/Context 之前,也是危险的,应始终伴随空检查。
我曾经有一个简单的方法来检查这个:
if (activity != null && !activity.isFinishing()) {
// safe
}
在 Jelly Bean (API 17 afaik) 之后,您还可以检查 activity.isDestroyed()
或类似内容(现在不记得了)。
如果您必须存储上下文(以便稍后执行一些与上下文相关的操作),请始终尝试存储应用程序上下文 (activity.getApplicationContext()),它是对 Application
的静态引用单例,不会泄漏。
话虽如此,请记住每种类型的上下文都有哪些限制。如有疑问,请将书签保存在 this 左右,特别是为了了解为什么尝试使用 Application 上下文扩充布局可能会产生意外结果。
更新:
如果你需要一个 common/generic 的地方来操作你的片段,请保持一个方便的 util class 像(伪代码):
public final class FragmentUtils {
private FragmentUtils() {
}
public static void add(FragmentActivity fragmentActivity, int layoutId, Fragment fragment) {
if (isContextInvalid(fragmentActivity)) {
return
}
FragmentTransaction fragmentTransaction = fragmentActivity.getSupportFragmentManager().beginTransaction();
fragmentTransaction.add(layoutId, fragment);
fragmentTransaction.commit();
}
public static void replace(FragmentActivity fragmentActivity, int layoutId, Fragment fragment) {
if (isContextInvalid(fragmentActivity)) {
return
}
// TODO: you do this one ;)
}
public static void remove(FragmentActivity fragmentActivity, Fragment fragment) {
if (isContextInvalid(fragmentActivity)) {
return
}
// TODO: you do this one ;)
if (fragment.isAdded()) {
…
}
}
public static void show(FragmentActivity fragmentActivity, Fragment fragment) {
// TODO: you do this one ;)
if (fragment.isAdded()) {
…
}
}
public static void hide(FragmentActivity fragmentActivity, Fragment fragment) {
// TODO: you do this one ;)
if (fragment.isAdded()) {
…
}
}
public boolean isContextInvalid(final Context context) {
if (context == null || context.isFinishing()) {
return true;
}
return false;
}
}
并将 null/checks 添加到您的上下文中。 (或类似)
注意上面的代码并不完整,我只是在这个编辑器里写的….
在 Android 平台中,GC(垃圾收集器)在留下 Activity 时会清除未使用的资源(即使您不希望这样做),因此您保存了实例,但是Activity 不再存在,您需要相应地思考 Android Lifecycle.
GC 是不可预测的,因为如果您实际使用 Activity 它不会消失,但一旦您不再看到它,它就可以随时被收集(擦除)。
Android 系统的基础包括精确实现生命周期的方法,以便能够随时清理内存而不会出现被销毁的问题 Activity,而不是 recreated ,如果适用,加载以前保存的状态。
我正在寻找一种通用方法来满足此异常。例如,如果用户保持非常快速地切换活动,这种情况总是会发生。因为显然有很多地方我们会尝试访问 activity 引用,当它为 null 时,应用程序会因此异常而崩溃。一种方法是每次访问 activity 引用时检查 "isFinishing()",我想知道是否有另一种更好和通用的方法来解决应用程序中的这个问题等级。
如果我的问题听起来很愚蠢或没有任何意义,请原谅我,但我想问没有坏处:)。
一切都与您如何为应用程序中的数据建模有关。 activity 实例数据只是临时数据,因此您应该查看以下备选方案,看看哪个更适合您的上下文:
您有会话级别的数据,这可以在单独的 class 中维护,可能是单例或在 Application 对象中。
如果您有需要持久保存的数据,请考虑 Android preferences 或数据库。
如果您希望在活动之间共享数据(不在应用程序级别),被调用者 Activity 应该 pass that via an intent.
从 OO 的角度考虑谁是该数据的合法所有者,或者是 activity 独有的临时数据(其他人无法访问)。
作为一般规则,Android 上下文应尽可能少地存储,并且仅在需要时使用。
如果您在尝试使用 Activity 上下文时遇到空异常或无效异常,这意味着您正在执行 Activity 的标准 Android 生命周期之外的操作。
由于生命周期的性质(异步),有时真的很难预测这些情况何时会出现……除非,您避免在生命周期事件之外执行操作上下文保证是活跃的。
例如:在异步任务甚至线程的 onPostExecute
方法中执行 Activity/Context 操作是一个定时炸弹。
作为一般规则,在尝试在生命周期方法(例如 onResume)之外使用 Activity/Context 之前,也是危险的,应始终伴随空检查。
我曾经有一个简单的方法来检查这个:
if (activity != null && !activity.isFinishing()) {
// safe
}
在 Jelly Bean (API 17 afaik) 之后,您还可以检查 activity.isDestroyed()
或类似内容(现在不记得了)。
如果您必须存储上下文(以便稍后执行一些与上下文相关的操作),请始终尝试存储应用程序上下文 (activity.getApplicationContext()),它是对 Application
的静态引用单例,不会泄漏。
话虽如此,请记住每种类型的上下文都有哪些限制。如有疑问,请将书签保存在 this 左右,特别是为了了解为什么尝试使用 Application 上下文扩充布局可能会产生意外结果。
更新:
如果你需要一个 common/generic 的地方来操作你的片段,请保持一个方便的 util class 像(伪代码):
public final class FragmentUtils {
private FragmentUtils() {
}
public static void add(FragmentActivity fragmentActivity, int layoutId, Fragment fragment) {
if (isContextInvalid(fragmentActivity)) {
return
}
FragmentTransaction fragmentTransaction = fragmentActivity.getSupportFragmentManager().beginTransaction();
fragmentTransaction.add(layoutId, fragment);
fragmentTransaction.commit();
}
public static void replace(FragmentActivity fragmentActivity, int layoutId, Fragment fragment) {
if (isContextInvalid(fragmentActivity)) {
return
}
// TODO: you do this one ;)
}
public static void remove(FragmentActivity fragmentActivity, Fragment fragment) {
if (isContextInvalid(fragmentActivity)) {
return
}
// TODO: you do this one ;)
if (fragment.isAdded()) {
…
}
}
public static void show(FragmentActivity fragmentActivity, Fragment fragment) {
// TODO: you do this one ;)
if (fragment.isAdded()) {
…
}
}
public static void hide(FragmentActivity fragmentActivity, Fragment fragment) {
// TODO: you do this one ;)
if (fragment.isAdded()) {
…
}
}
public boolean isContextInvalid(final Context context) {
if (context == null || context.isFinishing()) {
return true;
}
return false;
}
}
并将 null/checks 添加到您的上下文中。 (或类似) 注意上面的代码并不完整,我只是在这个编辑器里写的….
在 Android 平台中,GC(垃圾收集器)在留下 Activity 时会清除未使用的资源(即使您不希望这样做),因此您保存了实例,但是Activity 不再存在,您需要相应地思考 Android Lifecycle.
GC 是不可预测的,因为如果您实际使用 Activity 它不会消失,但一旦您不再看到它,它就可以随时被收集(擦除)。
Android 系统的基础包括精确实现生命周期的方法,以便能够随时清理内存而不会出现被销毁的问题 Activity,而不是 recreated ,如果适用,加载以前保存的状态。