简体   繁体   中英

Get a nullable var from a class

Let me start off by saying my Kotlin experience is limited. I am trying to get a nullable var from a class, but get a null pointer whenever I execute it.

Class code:

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
}

Initializing

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)
    ...
}

Accessing selected from MultiSpinner

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

The println reads null .

I have tried returning BooleanArray in stead of BooleanArray? for getSelected , but that just gave me a null pointer exception (as expected from the println reading).

I circumvented the problem for now by using category in the class and performing the manipulation inside the class. However, I would like to get the selected array in my main activity, and use its data to create my desired String outside of the class.

Why do I not get my selected data but instead a null pointer?

You have to access selected using the instance obtained from findViewById (the one already existing in your view hierarchy) instead of creating a completely new object by yourself:

val selected: BooleanArray? = spinnerCategory.getSelected()

Edit:

If you need to access selected outside the onCreate method simply store spinnerCategory as a property instead of a local variable:

private lateinit var spinnerCategory: MultiSpinner

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

Also Kotlin has a nice feature for Android called View Binding which allows you to omit calling findViewById and reference your views using their ids directly:

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

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

However in that case I'd recommend changing the view's id so it agrees with the Kotlin variable naming guidelines , eg to spinnerCategory as it's already being used.

You initialized selected with null meaning it can be nullable, so the compiler think it might possible that you will get null in this parameter. If you don't want it to be null you can define the variable like so:

private var selected: BooleanArray = false

Now selected parameter won't be nullable at any time.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM