I'm implementing a SpinnerAdapter
in Android project. So I have to override getView(i: Int, convertView: View, parent: ViewGroup)
method. So convertView
is here in order to reuse existing view and reduce memory usage and GC occurrences. So if it is null
I have to create view and use already created otherwise.
So in fact I have to write something like this (officially recomended by google):
if (view == null) {
view = View.inflate(context, R.layout.item_spinner, parent)
view.tag(Holder(view))
} else {
(view.tag as Holder).title.text = getItem(i)
}
But Kotlin does not allow to write to param. What I found on the internet is an official blog post that says that it is not possible since Feb, 2013.
So I'm wondering if there is any workaround ?
With the val keyword, we define a read-only variable. Its value cannot be altered later in the program. The data type is String, which is inferred from the string literal on the right side of the assignment. With the var keyword, we define a mutable variable.
Function parameter are immutable so can't be changed. Technically you could wrap a data class around the value and then use that a parameter making it mutable.
Mutable Variables A mutable variable is declared with the var keyword and represents a value that is expected to change throughout a program.
Mutable Parameters: It means that when a parameter is passed to the function using the caller function, then its value is bound to the parameter in the called function, which means any changes done to the value in that function will also be reflected in the parameter of the caller function.
There are two issues here.
First, you are mistakenly assuming that modifying view
in Java does anything outside of the current function scope. It does not. You setting that parameter to a new value affects nothing outside of the local function scope.
View getView(int i, View view, ViewGroup parent) {
// modify view here does nothing to the original caller reference to view
// but returning a view does do something
}
Next, in Kotlin all parameters are final
(JVM modifier, also same as final
modifier in Java). The Kotlin if
statement version of this code would be:
fun getView(i: Int, view: View?, parent: ViewGroup): View {
return if (view == null) {
val tempView = View.inflate(context, R.layout.item_spinner, parent)
tempView.tag(Holder(tempView))
tempView
} else {
(view.tag as Holder).title.text = getItem(i)
view
}
}
or avoiding the new local variable:
fun getView(i: Int, view: View?, parent: ViewGroup): View {
return if (view == null) {
View.inflate(context, R.layout.item_spinner, parent).apply {
tag(Holder(this)) // this is now the new view
}
} else {
view.apply { (tag as Holder).title.text = getItem(i) }
}
}
or
fun getView(i: Int, view: View?, parent: ViewGroup): View {
if (view == null) {
val tempView = View.inflate(context, R.layout.item_spinner, parent)
tempView.tag(Holder(tempView))
return tempView
}
(view.tag as Holder).title.text = getItem(i)
return view
}
or using the ?.
and ?:
null operators combined with apply()
:
fun getView(i: Int, view: View?, parent: ViewGroup): View {
return view?.apply {
(tag as Holder).title.text = getItem(i)
} ?: View.inflate(context, R.layout.item_spinner, parent).apply {
tag(Holder(this))
}
}
And there are another 10 variations, but you can experiment to see what you like.
It is considered less-than-a-good practice (but allowed) to shadow variables by using the same name, that is why it is a compiler warning. And why you see a change in the variable name above from view
to tempView
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With