从类中获取可为空的 var

Posted

技术标签:

【中文标题】从类中获取可为空的 var【英文标题】:Get a nullable var from a class 【发布时间】:2020-04-14 17:12:57 【问题描述】:

首先让我说我的 Kotlin 经验有限。我试图从一个类中获取一个可以为空的var,但是每当我执行它时都会得到一个空指针。

类代码:

class MultiSpinner : Spinner, OnMultiChoiceClickListener, OnCancelListener 

    private var items: List<String>? = null
    private var selected: BooleanArray? = null
    private var selectedNew: BooleanArray? = null
    private var defaultText: String? = null
    private var listener: MultiSpinnerListener? = null
    var category: String = "010"

    constructor(context: Context) : super(context) 

    constructor(arg0: Context, arg1: AttributeSet) : super(arg0, arg1) 

    constructor(arg0: Context, arg1: AttributeSet, arg2: Int) : super(arg0, arg1, arg2) 

    override fun onClick(dialog: DialogInterface, which: Int, isChecked: Boolean) 
        selectedNew!![which] = isChecked
    

    override fun onCancel(dialog: DialogInterface) 
        // refresh text on spinner
        val spinnerBuffer = StringBuffer()
        var allUnselected = true
        for (i in items!!.indices) 
            if (selected!![i]) 
                spinnerBuffer.append(items!![i])
                spinnerBuffer.append(", ")
                allUnselected = false
            
            selectedNew!![i] = selected!![i]
        

        var spinnerText: String?
        if (allUnselected) 
            spinnerText = defaultText
         else 
            spinnerText = spinnerBuffer.toString()

            /** Remove trailing comma*/
            spinnerText = spinnerText.substring(0, spinnerText.length - 2)
        
        val adapter = ArrayAdapter(
            context,
            R.layout.simple_spinner_item,
            arrayOf(spinnerText)
        )
        setAdapter(adapter)

        category = selected!!.joinToString(limit = selected!!.size, separator = "") it.toInt().toString()
        listener!!.onItemsSelected(selected)
    

    override fun performClick(): Boolean 
        val builder = AlertDialog.Builder(context)
        builder.setMultiChoiceItems(
            items!!.toTypedArray(), selectedNew, this
        )
        builder.setPositiveButton(R.string.ok
        )  dialog, _ -> selected = selectedNew!!.copyOf(); dialog.cancel() 
        builder.setNegativeButton(R.string.cancel
        )  dialog, _ -> dialog.cancel() 
        builder.setOnCancelListener(this)
        builder.show()
        return true
    

    fun setItems(
        items: List<String>, allText: String,
        listener: MultiSpinnerListener
    ) 
        this.items = items
        this.defaultText = allText
        this.listener = listener

        // one selected by default
        selected = BooleanArray(items.size) false
        selectedNew = BooleanArray(items.size) false
        for (i in selected!!.indices) 
            selected!![i] = false
            selectedNew!![i] = false
        

        selected!![0] = true
        selectedNew!![0] = true
        category = selected!!.joinToString(limit = selected!!.size, separator = "") it.toInt().toString()

        // all text on the spinner
        val adapter = ArrayAdapter(
            context,
            R.layout.simple_spinner_item, arrayOf(allText)
        )
        setAdapter(adapter)
    

    fun getSelected(): BooleanArray? 
        return selected
    

    interface MultiSpinnerListener 
        fun onItemsSelected(selected: BooleanArray?)
    

    private fun Boolean.toInt() = if (this) 1 else 0

正在初始化

override fun onCreate(savedInstanceState: Bundle?) 
    ...
    val spinnerCategory: MultiSpinner = findViewById(R.id.category_spinner)
    val categoryList: List<String> = resources.getStringArray(R.array.category).toList()

    spinnerCategory.setItems(categoryList, getString(R.string.default_category), this)
    ...


MultiSpinner 访问selected

val selected: BooleanArray? = MultiSpinner(this).getSelected()
println(selected)

println 读取null

我已经尝试返回 BooleanArray 而不是 BooleanArray? 来返回 getSelected,但这只是给了我一个空指针异常(正如 println 读数所预期的那样)。

我现在通过在类中使用category 并在类中执行操作来规避这个问题。但是,我想在我的主要活动中获取selected 数组,并使用它的数据在类之外创建我想要的字符串。

为什么我没有得到我的selected 数据,而是一个空指针?

【问题讨论】:

您的getSelected() 呼叫在哪里? onCreate也有吗? 现在只看到你的评论,它在onCreate之外的另一个函数中使用 【参考方案1】:

您必须使用从findViewById 获得的实例(视图层次结构中已经存在的实例)访问selected,而不是自己创建一个全新的对象:

val selected: BooleanArray? = spinnerCategory.getSelected()

编辑:

如果您需要在onCreate 方法之外访问selected,只需将spinnerCategory 存储为属性而不是局部变量:

private lateinit var spinnerCategory: MultiSpinner

override fun onCreate(savedInstanceState: Bundle?) 
    spinnerCategory = findViewById(R.id.category_spinner)
    ...

Kotlin 还为 android 提供了一个不错的功能,称为 View Binding,它允许您省略调用 findViewById 并直接使用它们的 id 引用您的视图:

override fun onCreate(savedInstanceState: Bundle?) 
    ...
    category_spinner.setItems(categoryList, getString(R.string.default_category), this)
    ...


private fun doSomethingWithSelected() 
    val selected: BooleanArray? = category_spinner.getSelected()

但是在这种情况下我建议更改视图的 id,使其符合 Kotlin 变量命名准则,例如到spinnerCategory,因为它已经被使用了。

【讨论】:

spinnerCategoryonCreate() 的作用域末尾被销毁时,我将如何访问它? @NSimons 我在回答中添加了一些额外的信息。 谢谢,我暂时使用了你的第一个建议,等我有时间再研究一下视图绑定【参考方案2】:

您使用null 初始化了selected,这意味着它可以为空,因此编译器认为您可能会在此参数中获得空值。 如果您不希望它为 null,您可以像这样定义变量:

private var selected: BooleanArray = false

现在selected 参数在任何时候都不能为空。

【讨论】:

问题不在于它是否可以包含null,而在于为什么我得到null 在这种情况下,您需要访问spinnerCategory,因为该对象是在onCreate 方法中创建的。如果你想从你应该做的方法之外访问它:var spinnerCategory: MultiSpinner override fun onCreate(savedInstanceState: Bundle?) ... spinnerCategory: = findViewById(R.id.category_spinner) val categoryList: List&lt;String&gt; = resources.getStringArray(R.array.category).toList() spinnerCategory.setItems(categoryList, getString(R.string.default_category), this) ... 谢谢,这行得通(有一些补充)。使用 private lateinit var spinnerCategory: MultiSpinner 成功了。

以上是关于从类中获取可为空的 var的主要内容,如果未能解决你的问题,请参考以下文章

如何从数据库中获取可为空的 DateTime

c#静态类中的8个可为空的引用类型

为啥 TargetNullValue 更新可为空的 Source

检查JSON var是否具有可为空的密钥(Twitter Streaming API)

尝试解析可为空的字段时出现 AvroTypeException

在 Typescript 中将可为空的对象值转换为字符串