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?