处理"活动已被破坏" (java.lang.IllegalStateException)异常?

时间:2015-03-27 15:31:01

标签: java android android-activity illegalstateexception

我正在寻找一种解决此异常的通用方法。如果用户例如非常快速地保持切换活动,则总会发生这种情况。因为很明显有很多地方我们会尝试访问活动引用,当它为空时,应用程序会因此异常而崩溃。一种方法是每次访问活动参考时检查" isFinishing()" ,我想知道在应用程序级别上是否有另一种更好和通用的方法来解决此问题。

请原谅我,如果我的问题听起来很愚蠢,或者没有任何意义,但我想问:)没有任何伤害。

3 个答案:

答案 0 :(得分:9)

作为一般规则,Android上下文应尽可能少地存储 并仅在需要时使用

如果您在尝试使用“活动”上下文时遇到空或无效异常,则表示您正在执行活动的标准Android生命周期之外的操作。

由于生命周期的特性(异步),有时很难预测何时会出现这些情况... 除非,否则您将避免在保证上下文的生命周期事件之外执行操作活。

例如:在onPostExecute asynctasks甚至线程的方法中执行活动/上下文操作,是一个定时炸弹。

作为一般规则,在尝试在生命周期方法之外使用Activity / Context之前(例如onResume),也是危险的,并且应始终伴随null检查。

我曾经有一个简单的方法来检查这个:

if (activity != null && !activity.isFinishing()) {
   // safe
}

在Jelly Bean之后(API 17 afaik)你也可以检查activity.isDestroyed()或类似的(现在不记得)。

如果必须存储上下文(稍后执行某些与上下文相关的操作),请始终尝试存储应用程序上下文(activity.getApplicationContext()),它是对Application单例的静态引用,并且它赢了不要泄漏。

话虽如此,请记住每种类型的上下文有哪些限制。如有疑问,请将书签保留到this周围,特别是要了解为什么尝试使用应用程序上下文来扩充布局可能会产生意外结果。

<强>更新

如果你需要一个通用/通用的地方来操作你的片段,请保留一个方便的util类,如(伪代码):

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添加到您的上下文中。 (或类似) 注意上面的代码不完整,我只是在这个编辑器里写了这个......

答案 1 :(得分:1)

关于如何为应用程序中的数据建模。活动实例数据只是临时的,因此您应该查看以下备选方案,以了解哪种方法更适合您的上下文:

  • 您有会话级数据,可以在单独的类中维护,可能是单个类或Application对象。

  • 如果您有数据,则需要考虑Android preferences或数据库。

  • 如果您希望在活动之间共享数据(不是在应用程序级别),则被调用者活动应pass that via an intent

从OO的角度考虑谁是该数据的合法拥有者,或者仅仅是活动私有的临时数据(并且其他人无法访问)。

答案 2 :(得分:0)

在Android平台中,GC(垃圾收集器)在离开活动时(即使你不期望)也会清除未使用的资源,所以你保存了实例,但是Activity不再存在,你需要相应地考虑Android Lifecycle.

GC不可预测,因为如果您实际使用的是活动,它不会消失,但是一旦您停止看到它,就可以随时收集(删除)。

Android系统的基础知识包括精确实现生命周期的方法,以便能够随时清理内存而不会出现被破坏的活动的问题,而是recreated,如果适用,加载以前保存的状态。