Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I make method param mutable in Kotlin?

Tags:

android

kotlin

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 ?

like image 634
oleg.semen Avatar asked May 22 '17 09:05

oleg.semen


People also ask

How do you make a mutable variable in Kotlin?

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.

How do I change the parameter value in Kotlin?

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.

Which keyword creates a mutable variable in Kotlin?

Mutable Variables A mutable variable is declared with the var keyword and represents a value that is expected to change throughout a program.

What is a mutable parameter?

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.


1 Answers

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

like image 121
2 revs Avatar answered Sep 30 '22 11:09

2 revs