java—由于fragment类中缺少公共construcotr方法,在android中旋转设备后出现异常

mpgws1up  于 2021-07-08  发布在  Java
关注(0)|答案(2)|浏览(300)

我用一个包含片段的活动编写了一个非常简单的程序。我将片段构造函数设置为私有的,并使用静态newinstance()方法返回片段。当我转动电话时问题就开始了。我得到一个例外说:
无法启动活动组件信息{com.example.todeleteimmeditaley/com.example.mainactivity}:androidx.fragment.app.fragment$instantiationexception:无法示例化片段com.example.datesfragment:找不到片段构造函数
我调试了程序,发现异常在oncreate方法的第一行(调用super.oncreate()时)。有人可以解释为什么片段必须有一个构造函数,为什么异常发生在super.oncreate()阶段?

nszi6y05

nszi6y051#

当您旋转设备时 Activity 将被摧毁和重建。部分原因是破坏和重建 Fragment 您的活动正在托管。
在重新创建步骤中,android框架需要示例化 Fragment . 默认情况下,它是通过调用片段的无参数构造函数来实现的。这意味着这个构造函数必须(a)存在并且(b)是 public .
碎片的重新创造是由 super.onCreate() 你的活动。
一般建议是建立一个 newInstance() 工厂方法(正如您所做的那样),但是不要使用默认构造函数(即,不要使其 private ). 是的,这意味着仍然有可能有人直接调用构造函数,这是您不想要的,但是如果您不想参与其中,则必须这样做 FragmentFactory .

评论中的进一步问题

这是否意味着在oncreate中,我应该在添加和提交之前检查容器是否已经包含片段?因为据我所知,oncreate().super将还原旧片段。
这里我的建议是只提交片段事务一次,即第一次启动活动时。通常,这是通过检查 savedInstanceState 提交事务之前,bundle为空:

if (savedInstanceState == null) {
    getSupportFragmentManager().beginTransaction()
            .replace(R.id.foo, FooFragment.newInstance(...))
            .commit();
}

因为你的片段是你活动示例状态的一部分,任何时候 savedInstanceState 不是 null )将自动为您处理。
为什么在newinstance方法中最好将片段需要的信息添加到bundle中,而不是将它们存储为片段的成员(属性)?
一切都回到了android框架需要创建片段的新示例的事实上。如果只是在片段上设置了成员字段,那么android框架将不知道这些字段,并且无法保存或还原它们。
然而 arguments 捆绑包是android所知道的。参数被认为是片段示例状态的一部分(因此也是包含活动示例状态的一部分),并将被自动保存和还原。这就是为什么只能将某些类型的数据放入 arguments 束;android只知道如何在这个过程中“写”和“读”特定类型的数据。

xienkqul

xienkqul2#

在java中
如果一个类没有定义任何构造函数,那么在编译时,编译器将生成一个没有参数的构造函数(我们通常称之为默认构造函数、无参数构造函数或零参数构造函数)。
如果类定义了任何具有参数的构造函数,那么在编译时,编译器将不会生成默认构造函数。
有人能解释为什么片段必须有构造器吗?
如果片段没有收到任何参数,则不需要定义构造函数。
为什么异常发生在super.oncreate()阶段?
在android中,当系统需要重新创建一个活动时,有几种情况,例如。
当配置改变时,如用户旋转屏幕方向或改变语言。
当系统内存不足时
在重新创建活动时,系统将创建该活动的新示例,然后调用活动生命周期,第一个示例将是 onCreate() 回拨。在活动(例如mainactivity)中,您需要调用 super.onCreate() 它的父母。此语句将还原由活动管理的所有片段(例如,在您的示例中是datesframpent)。
因为这是mainactivity的一个新示例,所以它还需要为所有托管片段(包括datesfragment)创建一个新示例。为此,它们将调用默认参数构造函数。
但是在datesfragment中,您将默认构造函数设置为private,这意味着它只能在该类中访问,系统无法调用datesfragment类的构造函数,因此它们会抛出instantiationexception。
解决方案:
如果您的片段没有收到任何参数,请不要定义任何构造函数
如果需要将参数传递给片段,那么使用默认构造函数和setarguments(bundle)

相关问题