【问题标题】:Kotlin UninitializedPropertyAccessException when trying to extract current spinner item尝试提取当前微调器项时出现 Kotlin UninitializedPropertyAccessException
【发布时间】:2020-11-16 21:01:32
【问题描述】:

我有两个微调器,第二个根据第一个的值更改它包含的项目数组。我需要另一个类中第二个微调器的当前项目(稍后我可能还需要另一个类中第一个微调器的当前项目,但现在我只是想得到第二个),所以我试图将其保存在变量中。

我全局声明

private lateinit var instrumentSpinner : Spinner
private lateinit var tuningSpinner : Spinner
internal lateinit var curTuning : String

这里是日志:

kotlin.UninitializedPropertyAccessException: lateinit property curTuning has not been initialized
        at com.example.tuner.MainActivity.getCurTuning$app_debug(MainActivity.kt:31)
        at com.example.tuner.PitchProcessing.tuneGuitar(PitchProcessing.kt:16)
        at com.example.tuner.MainActivity$onCreate$pdh$1$1.run(MainActivity.kt:130)
        at android.os.Handler.handleCallback(Unknown Source:2)
        at android.os.Handler.dispatchMessage(Unknown Source:4)
        at android.os.Looper.loop(Unknown Source:208)
        at android.app.ActivityThread.main(Unknown Source:107)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(Unknown Source:11)
        at com.android.internal.os.ZygoteInit.main(Unknown Source:274)

第 31 行是该变量 (curTuning) 的声明,PitchProcessing 中的第 16 行尝试将该变量与 MainActivity().curTuning 一起使用,并在第 130 行中调用 PitchProcessing。

这是我的 onCreate 中的两个微调器:

        // initializing instrument spinner
        instrumentSpinner = findViewById(R.id.instrument_spinner)
        ArrayAdapter.createFromResource(
            this,
            R.array.instruments_array,
            android.R.layout.simple_spinner_dropdown_item
        ).also { adapter ->
            adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
            instrumentSpinner.adapter = adapter
        }
        instrumentSpinner.onItemSelectedListener = object : OnItemSelectedListener {
            override fun onItemSelected(
                parent: AdapterView<*>,
                view: View?, pos: Int, id: Long
            ) {
                when (parent.getItemAtPosition(pos).toString()) {
                    "Guitar" -> ArrayAdapter.createFromResource(
                        this@MainActivity,
                        R.array.tuning_array_guitar,
                        android.R.layout.simple_spinner_dropdown_item
                    ).also { adapter ->
                        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
                        tuningSpinner.adapter = adapter
                    }
                    "Bass" -> ArrayAdapter.createFromResource(
                        this@MainActivity,
                        R.array.tuning_array_bass,
                        android.R.layout.simple_spinner_dropdown_item
                    ).also { adapter ->
                        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
                        tuningSpinner.adapter = adapter
                    }
                    "Ukulele" -> ArrayAdapter.createFromResource(
                        this@MainActivity,
                        R.array.tuning_array_ukulele,
                        android.R.layout.simple_spinner_dropdown_item
                    ).also { adapter ->
                        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
                        tuningSpinner.adapter = adapter
                    }
                }
            }
            override fun onNothingSelected(parent: AdapterView<*>?) {
                // Do nothing.
            }
        }

        // initializing tuning spinner
        tuningSpinner = findViewById(R.id.tuning_spinner)
        ArrayAdapter.createFromResource(
            this,
            R.array.tuning_array_guitar,
            android.R.layout.simple_spinner_dropdown_item
        ).also { adapter ->
            adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
            tuningSpinner.adapter = adapter
        }
        tuningSpinner.onItemSelectedListener = object : OnItemSelectedListener {
            override fun onItemSelected(
                parent: AdapterView<*>,
                view: View?, pos: Int, id: Long
            ) {
                curTuning = tuningSpinner.getItemAtPosition(pos).toString()
            }
            override fun onNothingSelected(parent: AdapterView<*>?) {
                // Do nothing.
            }
        }

有人可以帮我解决这个问题吗?我已经尝试了好几个小时,所以任何帮助将不胜感激,谢谢!

【问题讨论】:

    标签: java android kotlin exception spinner


    【解决方案1】:

    当使用 lateinit 时,您必须先初始化 lateinit 变量,然后再使用它,否则会出现异常

    异常 kotlin.UninitializedPropertyAccessException: lateinit property curTuning 表示您在初始化之前尝试访问 curTuning 变量,因此引发了异常。

    如果您不确定用什么来初始化 curTuning,则将其设为 可为空 变量,但请确保 更新并为其设置适当的值并处理 nullability 否则会有 NullPointerException

    【讨论】:

    • 我的印象是我在使用它之前确实初始化了 curTuning,因为我只在第 130 行的方法调用中使用它 - 使它可以为空,我猜微调器不会自动初始化第一个项目?
    • 从您的代码中,我了解到您正在尝试在 tuningSpinner.onItemSelectedListener 内的第 130 行初始化 curTuning。这样做是行不通的,因为当您的应用启动时,它仍然会找到一个 uninitialized 属性,它恰好是 curTuning 变量,结果会引发 exception你的应用程序崩溃了。您必须使其 nullable 或在 onCreate 中为 curTuning 设置一些值,然后再更新它。
    【解决方案2】:

    用 null 分配 curTuning 可以消除异常,但不能解决问题本身。但是像这样使用 curTuning

     object CurTuning {
        var curTuning : String? = null
     }
    

    适用于我的其余代码(如果我使用 CurTuning.curTuning 进行 curTuning 处理)

    编辑:有人指出这是多余的,我可以直接将 curTuning 放入我的课程中,但这在我的情况下不起作用。但我注意到,当使用伴随对象时,我不需要变量可以为空。

    【讨论】:

    • 这样做可能会奏效,但这是不必要的。您正在创建一个 CurTuning 的单个实例(伴随对象),它有一个可为空的 var curTuning .. 这是冗余代码,可以在类中完成同样的事情本身没有创建伴随对象。
    • 你能解释一下为什么这会起作用,而不是直接做 var curTuning : String? = null 吗?我不知道为什么伴生对象起作用而直接做却不起作用,但这就是我获得所需行为的方式
    • kotlin 中的对象是一个 singleton,相当于 Java 中的 static。伴随对象用于在类内部放置应该是静态的变量和方法(对于类的所有实例具有相同的值或签名)。在您的情况下,您已在冗余的伴随对象中将 var curTuning 设置为 null。当引用CurTuning.curTuning 时,您实际上是在引用companion object 中的变量,该变量已设置为null,现在正在更新它。相同的可为空签名在类内部工作,无需使用伴随对象。
    • 当不使用伴生对象时,无论用户选择如何,引用可空变量总是给我 null,但在伴生对象中我确实得到了当前用户的选择。但是我只是注意到,在使用伴随对象时,我不需要使变量可以为空以使其工作
    • 当您使用可空变量时,您必须处理 null 检查。如果创建一个变量lateinit,你必须先初始化它,如果你想避免both nullable and lateinit,那么你的变量是var而不是有效。使用 var 您可以更改变量引用。这就是您当前在伴生对象中所做的事情。这可以在类本身中完成。 var curTuning:String ="Initial String value" 和稍后的某个时间点 curTuning = "new Updated String value" 因为类型是 String
    猜你喜欢
    • 1970-01-01
    • 2014-03-26
    • 1970-01-01
    • 2021-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-14
    相关资源
    最近更新 更多