Stephen__T
Stephen__T

Reputation: 2032

How do I initialize a collection value for a MutableLiveData object?

class Foo : ViewModel() {
   val bars: MutableLiveData<ArrayList<Bar>> = MutableLiveData()
     get() {
       if(field.value == null) {
         field.setValue(ArrayList()) // NullPointerException
       }
     }
}

class FooTest(){
   @Test fun itShouldNotBlowUp() {
     Foo() //nullPointerException

   }

}

I don't understand how to initialize the value of a MutableLiveData object. I've tried to lazily initialize it via the getter and with an init block. Both approaches throw a null pointer when setting the value. bars is not null however.

Here is the stacktrace:

java.lang.NullPointerException
at android.arch.core.executor.DefaultTaskExecutor.isMainThread(DefaultTaskExecutor.java:58)
at android.arch.core.executor.ArchTaskExecutor.isMainThread(ArchTaskExecutor.java:116)
at android.arch.lifecycle.LiveData.assertMainThread(LiveData.java:434)
at android.arch.lifecycle.LiveData.setValue(LiveData.java:279)
at android.arch.lifecycle.MutableLiveData.setValue(MutableLiveData.java:33)
at org.Foo.<init>(Foo.kt:10)
at org.FooTest.ShouldNotBlowUp(FooTest.kt:3)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

How do I initialize the ArrayList and set it as the value of bars?

Upvotes: 1

Views: 3616

Answers (2)

Jesr2104
Jesr2104

Reputation: 31

The answer to the question is: if you want to give it an empty value clearly, but the variable is not null and you can at least use it without breaking the program.

to create a variable:

val myVariable = MutableLiveData<ArrayList<String>>()

Well, now you only have to pass the constructor of the empty list within the type parentheses so that your variable does not remain with a Null value.

val myVariable = MutableLiveData<ArrayList<String>>(arrayListOf())

I know it's an old question but in case it can help someone, it helped me discover this ;)

Upvotes: 0

Ilya E
Ilya E

Reputation: 752

Maybe the reason is that you are trying to run this in the test. Your sample fails in DefaultTaskExecutor.isMainThread(), that looks like this:

public boolean isMainThread() {
    return Looper.getMainLooper().getThread() == Thread.currentThread();
}

So Looper.getMainLooper() returns null in the test environment.

And also, have you tried to initialize property via 'lazy' delegate?

val bars: MutableLiveData<List<Bar>> by lazy {
    MutableLiveData<List<Bar>>().apply {
        value = emptyList()
    }
}

That works fine in my case and feels more idiomatic

Upvotes: 3

Related Questions