【问题标题】:Is it possible to use newInstance() on an Activity in Android Kotlin是否可以在 Android Kotlin 中的 Activity 上使用 newInstance()
【发布时间】:2021-06-10 04:38:49
【问题描述】:

我实际上是 android 新手。我现在对如何在片段中实现 newInstance() 感到困惑。我在这里有 2 个片段和 1 个活动:

  • 片段 A 作为抽象类
  • 片段 B 作为包含参数的主片段类
  • MainActivity.kt 作为 Activity

所以我得到了这样的错误日志:

Caused by androidx.fragment.app.Fragment$e: Unable to instantiate fragment : could not find Fragment constructor
............
Caused by java.lang.NoSuchMethodException: <init> []
       at java.lang.Class.getConstructor0

根据日志,我认为问题出在我没有初始化任何 0-arg 构造函数的片段上。所以正因为如此,我想在我的片段中为 newInstance() 添加一个伴随对象,但我不能,这是我的 FragmentA.kt 和 FragmentB.kt :

FragmentA.kt

abstract class FragmentA: BottomSheetDialogFragment() {

companion object {
fun newInstance(): FragmentA{
    return FragmentA()  //Got a red mark here, because I cannot create newInstance() in an abstract class
}
}
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setStyle(DialogFragment...,getStyle)
    }

}

FragmentB.kt

class FragmentB(val Parameterss: AnyParametersHere) : FragmentA() {
    
    companion object {
    fun newInstance(): FragmentB{
        return FragmentB()  //Got a red mark here, because it requires parameter inside the FragmentB()
    }
    }
        override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        val dialog = super.onCreateDialog(savedInstanceState)
        ..................................................................
        return dialog

        }
    
    }

MainActivity.kt 在 MainActivity.kt 中,是否可以将 newInstance() 添加到其伴随对象中?如果不是,这种情况的最佳解决方案是什么?

class MainActivity : AppCompatActivity() {

companion object {
        fun newInstance(): MainActivity {
            return newInstance()
        }
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    ...................................
    val fragmentB= FragmentB(this)
        fragmentB.show(supportFragmentManager, FragmentB.TAG)

    }

}

我很困惑,如果您有任何更好的解决方案,我会很感激。谢谢

【问题讨论】:

    标签: java android kotlin android-fragments


    【解决方案1】:

    这里有很多不同的地方,我建议你阅读更多关于这个主题的内容。我将帮助您消除疑虑。让我们从您的代码开始。

    首先FragmentAFragmentA 是一个抽象类,因此当您遇到错误时

    无法实例化片段

    您不能创建抽象类的实例,因为它没有完整的实现。如果是这样,则不应首先将其标记为摘要。您应该从FragmentB中的抽象类扩展@

    现在来到 FragmentB

    class FragmentB(val Parameterss: AnyParametersHere) : FragmentA() {
    

    正如您在内部看到的,您在其构造函数中接受参数。现在来到你的newInstance() 方法。代码如下:

    fun newInstance(): FragmentB{
            return FragmentB()
        }
    

    你在这里得到了一个错误或读取标记是正确的,因为你创建了一个 FragmentB 的实例,但你没有在它的构造函数中传递任何参数,而你在它的构造函数中放入了任何参数。

    现在找到正确的模式,我们通常在 Fragment 中使用newInstance,当我们需要将arguments从一个片段传递到另一个片段时,我们使用Bundles,我们通过newInstance分配

    这是一个示例代码。

    companion object {
            fun newInstance() = FragmentB().apply {
                arguments = Bundle().apply {
                    // Put values here in a key value pair.
                }
            }
        }
    

    然后你会得到一个FragmentB 的实例作为FragmentB.newInstance()。您将不得不阅读有关此主题的更多信息。在 Fragment 之间传输数据的方法不止一种。

    来到你的MainActivity,你不需要newInstance,因为在Activity之间你可以直接使用Intents并在需要时以这种方式传输数据。

    【讨论】:

    • 但是要在 FragmentB 中创建 newInstance(),我需要在其中添加参数吗 @che10 ?像这样companion object { fun newInstance() = FragmentB(parameters).apply { arguments = Bundle().apply { // Put values here in a key value pair. } } }
    • 是的,您可以通过在该块中使用 put 函数来使用键值对添加参数。像 putString()putInt() 这样的。
    • 对不起,我有点困惑,所以我知道我必须使用 putString()putInt() 添加参数,但我仍然在 fun newInstance() = FragmentB().apply { 中得到红色标记。我不知道如何解决这个问题。因为 FragmentB() 需要像 FragmentB(parameters = ) 这样的参数,而我没有事先初始化参数
    • 如果我可以说,我的情况有点类似于这个问题stackoverflow.com/questions/67899930/…
    • 你能澄清一下你要添加什么样的参数吗?您需要根据它们的类型添加它们。就像如果它是一个 Integer 那么你将使用 putInt() 如果它是一个 String 那么你将使用 putString() 等等。您的 newInstance() 方法将被修改。假设您必须添加字符串,然后它将是newInstance(stringToAdd: String),然后在其中您可以将其添加为putString("Your Key here", stringToAdd)
    【解决方案2】:

    FragmentB 的构造函数必须有参数。片段由操作系统使用空构造函数重新创建。您的newInstance() 函数可以通过捆绑将数据传递给片段,如果操作系统重新创建您的片段,它将恢复相同的捆绑。使用 requireBundle() 获取参数并将它们分配给 Fragment 的第一个入口点中的属性(onCreateView()onViewCreated()onCreateDialog())。

    一个常见的错误是给你的 Fragment 两个构造函数,一个是空的,一个是你需要的参数,另一个是在newInstance() 中使用参数。这样做的问题是,当操作系统使用空构造函数重新创建 Fragment 时,您的参数将丢失。操作系统只恢复Bundle,不恢复构造函数的参数,因为它专门使用空构造函数。

    请注意,捆绑参数必须是受支持的类型之一,即所有“原始”类、字符串、Parcelables、上述任何一种的数组以及 Serializeables。

    如何使用需要一些值的片段执行此操作的示例:

    class MyFragment: Fragment() {
    
        companion object {
            private const val SOME_ARG_KEY = "SOME_ARG_KEY"
            private const val SOME_OTHER_ARG_KEY = "SOME_OTHER_ARG_KEY"
    
            fun newInstance(someArgument: Long, someOtherArgument: String)
                = MyFragment().apply { 
                    arguments = bundleOf(
                        SOME_ARG_KEY to someArgument,
                        SOME_OTHER_ARG_KEY to someOtherArgument,
                    )
                }
        }
    
        lateinit var someArgument: Long
        lateinit var someOtherArgument: String
    
        //...
    
        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            with (requireArguments()) {
                someArgument = getLong(SOME_ARG_KEY)
                someOtherArgument = getString(SOME_OTHER_ARG_KEY)
            }
        }
    }
    

    【讨论】:

    • 我知道了,但是你有什么可以参考的例子或参考资料吗?谢谢
    • @LieAnaWijaya 我添加了一个示例。
    猜你喜欢
    • 2021-11-12
    • 2017-12-18
    • 2015-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-26
    • 1970-01-01
    相关资源
    最近更新 更多