Activity 似乎是在应用程序对象之前创建的

Posted

技术标签:

【中文标题】Activity 似乎是在应用程序对象之前创建的【英文标题】:Activity seems to be created before application object 【发布时间】:2019-04-09 17:09:43 【问题描述】:

我在 Play 商店中收到了一些崩溃报告,起初我觉得这很疯狂。 由于 NullPointerException,某些活动(在 1 种情况下是广播接收器)在 onCreate()/onResume() 中崩溃。

这些活动使用静态方法,而这些方法又使用 Application 单例 [for context],但返回的对象为 null,就像应用程序对象根本不存在一样。据我了解,应用程序应该始终有一个实例。

我的代码很普通,应用在其onCreate()中设置了一个静态字段,Activity调用的类使用MyApplication.getInstance()返回应用对象。

MyApplication.getInstance() 从活动调用时如何返回 null?我不知道这是怎么发生的。

当然,我无法复制这次崩溃。 这主要发生在 android 6 中,但我有一些来自 Android 8 和 9 的报告。

【问题讨论】:

为什么需要应用上下文?您可以改用您的活动的上下文吗?取决于应用程序上下文通常不是您想要做的事情。 【参考方案1】:

我猜你正在做这个question 中投票最多的答案。 但是,您应该看到许多人在 cmets 中警告的内容:

缺点是不能保证非静态 onCreate() 将在一些静态初始化之前被调用 代码尝试获取您的 Context 对象。 这意味着您的调用代码 需要准备好处理失败的空值 这个问题的重点。 – 梅琳达格林

.

看到这个答案有多少赞成票,真是令人沮丧。 Y你永远不应该将静态实例保存到上下文中——为了证明,尝试使用 Leak Canary (github.com/square/leakcanary) 并找出由此引起的内存泄漏。 @people-with-enouhg-rep-and-Android-knowledge,请重新查看此答案并采取相应措施。保证初学者可以使用它,这是很简单的错误。 – Crearo Rotar

您应该:

尽可能使用您的 Activity 上下文并将其传递给需要它的任何其他类。

或者,我真正推荐的是,使用Dagger2 设置依赖注入。刚开始学习有点困难,但是有很多信息和教程可以帮助您入门。正确设置 Dagger 后,您需要以 null 安全的方式访问应用程序上下文,只需将其注入相应的类中,如下所示:

public class MyClass 

    @Inject
    Context context;


    ...


【讨论】:

【参考方案2】:

作为关于 dagger 依赖注入的其他答案的替代方案,我只是想举一个例子,以老式的方式从活动中获取上下文。如果您将 context 声明为成员变量,它将在您的整个活动中可用,并且可以根据需要传递给其他类:

public class ExampleActivity extends AppCompatActivity 

    private Context mContext;

    @Override protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_example);
        mContext = this;
    

【讨论】:

【参考方案3】:

我想我找到了原因。在 Android 6 自动恢复未初始化应用程序中,问题是相同的,他们确定原因是 Android 6 中引入的自动备份功能。基本上,从备份恢复后,应用程序以一种奇怪的方式重新启动,其中Application 对象不是在 Activity 之前创建的。我们现在可以重现问题并禁用备份解决问题。

【讨论】:

以上是关于Activity 似乎是在应用程序对象之前创建的的主要内容,如果未能解决你的问题,请参考以下文章

错误的窗口令牌,您无法在创建 Activity 之前或隐藏之后显示对话框

从 Activity 导航到 Fragment 并返回到 Activity 导致该 Activity 被多次创建

现在不推荐使用 TabActivity 使用 Fragments 创建选项卡

Activity的最佳实践

1.4.4 重新创建Activity

android setContentView处理流程