I tried initializing my LiveData object and it gives the error: "LiveData is abstract, It cannot be instantiated"
LiveData listLiveData = new LiveData<>();
In a ViewModel, you may want to use MutableLiveData instead.
E.g.:
class MyViewModel extends ViewModel {
private MutableLiveData<String> data = new MutableLiveData<>();
public LiveData<String> getData() {
return data;
}
public void loadData() {
// Do some stuff to load the data... then
data.setValue("new data"); // Or use data.postValue()
}
}
Or, in Kotlin:
class MyViewModel : ViewModel() {
private val _data = MutableLiveData<String>()
val data: LiveData<String> = _data
fun loadData() {
viewModelScope.launch {
val result = // ... execute some background tasks
_data.value = result
}
}
}
Since it is abstract (as #CommonsWare says) you need to extend it to a subclass and then override the methods as required in the form:
public class LiveDataSubClass extends LiveData<Location> {
}
See docs for more details
Yes, you cannot instantiate it because it is an abstract class. You can try to use MutableLiveData if you want to set values in the live data object. You can also use Mediator live data if you want to observe other livedata objects.
You need to use MutableLiveData and then cast it to its parent class LiveData.
public class MutableLiveData
extends LiveData
[MutableLiveData is] LiveData which publicly exposes setValue(T) and postValue(T) method.
You could do something like this:
fun initializeLiveData(foo: String): LiveData<String> {
return MutableLiveData<String>(foo)
}
So then you get:
Log.d("now it is LiveData", initializeLiveData("bar").value.toString())
// prints "D/now it is LiveData: bar"
I think much better way of achieving this is by using, what we call is a Backing Property, to achieve better Encapsulation of properties.
Example of usage:
private val _userPoints = MutableLiveData<Int>()// used as a private member
val userPoints: LiveData<Int>
get() {
return _userPoints
} //used to access the value inside the UI controller (Fragment/Activity).
Doing so maintains an editable MutableLiveData private to ViewModel class while, the read-only version of it is maintained as a LiveData, with a getter that returns the original value.
P.S. - notice the naming convention for both fields, using an (_) underscore. This is not mandatory but advised.
Related
I want to generate a String in a function in my viewmodel and send it to the fragment associated to this viewmodel as a LiveData, how can I do it?
For example, my viewmodel:
class MaskViewModel : ViewModel() {
var mask: MutableLiveData<String> = newQuestion()
fun newQuestion(): MutableLiveData<String>{
mask.value="255"
return mask
}
}
And the observer in my fragment:
maskviewModel.mask.observe(viewLifecycleOwner){ result ->
binding.textView3.text=result
}
Your function should not return a LiveData or replace the existing LiveData. You should only have a single LiveData instance so when the Fragment observes it, it will get all future changes.
class MaskViewModel : ViewModel() {
val mask = MutableLiveData<String>()
fun newQuestion() {
mask.value="255"
}
}
But it is better encapsulation not to expose your LiveData as being mutable outside the class, so this is better:
class MaskViewModel : ViewModel() {
private val _mask = MutableLiveData<String>()
val mask: LiveData<String> get() = _mask
fun newQuestion() {
_mask.value="255"
}
}
You appear to be all set up to observe any changes to your mask variable within your fragment. To set a new String to it, simply call mask.postValue(myString) within your function. This will trigger your observer, which will receive the new value of mask as result.
Additionally, you are not assigning an instance of MutableLiveData to mask. Your newQuestion() never creates an instance of MutableLiveData, but rather tries to access it while it is still null.
Instantiate it this way: val mask: MutableLiveData<String> = MutableLiveData(). Then you can call .postValue() on it. I've changed it to val because you can keep it as the same reference but still change the value within it. Keep it as var only if you wish to reassign it to a new MutableLiveData at some point, which is unlikely.
As #Tenfour04 mentions in his answer, your function should not return LiveData.
instead of returning the string from your viewModel , you could return it's id , and call the string from fragment.
in the ViewModel
private val _mask = MutableLiveData<Int>()
val mask: LiveData<Int> get() = _mask
fun newQuestion() {
_mask.value = R.string.mask_value
}
in the Fragment
maskviewModel.mask.observe(viewLifecycleOwner){ id ->
binding.textView3.text = requireContext().getString(id)
}
I'm fairly new on the Android Room, which uses LiveData that I'm also not familiar with. I noticed that on the tutorials, the data returned is using LiveData wrapper, like this:
#Dao
interface PersonDao {
#Query("SELECT * FROM person")
fun getAll(): LiveData<List<Person>>
}
Then to read the data, I use this code:
class PersonListActivity: AppCompatActivity() {
List<Person> personList = listOf()
init {
val db = RoomDatabase.getDatabaseInstance()
db.personDao.getAll().observe(this, Observe<List<Person>> { data ->
personList = data
})
}
}
The problem is the IDE raise error "type mismatch". Required: LifeCycleOwner. Found: PersonListActivity. I don't understand how the tutorials can casually supply "this" into the observe owner parameter. I've also tried to supply context and applicationContext into the owner parameter and it doesn't work.
After I examine the LifeCycleOwner class, I tried to add the LifeCycleOwner implementation. But then the class requires getLifeCycle() function to be implemented. So I'm back at zero.
class PersonListActivity: AppCompatActivity(), LifeCycleOwner {
List<Person> personList = listOf()
init {
val db = RoomDatabase.getDatabaseInstance()
db.personDao.getAll().observe(this, Observe<List<Person>> { data ->
personList = data
})
}
override fun getLifeCycle() {
// what should I return here??????
}
}
Why all the tutorials I read about LiveData don't mention anything at all about LifeCycleOwner? Am I using the wrong observe function here?
public abstract class LiveData<T> {
...
#MainThread
public void observe(#NonNull LifecycleOwner owner, #NonNull Observer<? super T> observer) { ... }
...
}
Since the version 1.1.0 (excluding the not-stable releases) of androidx.appcompat:appcompat, AppCompatActivity implements LifecycleOwner (see ComponentActivity). So you can use this when calling:
db.personDao.getAll().observe(this, Observe<List<Person>> { data ->
personList = data
})
Without implementing anything else.
Furthermore, I would move those lines in Activity.onCreate().
Consider the following ways to expose MutableLiveData:
Method A
class ThisViewModel : ViewModel() {
private val _someData = MutableLiveData(true)
val someData: LiveData<Boolean>
get() = _someData
}
// Decompiled Kotlin bytecode
public final class ThisViewModelDecompiled extends ViewModel {
private final MutableLiveData _someData = new MutableLiveData(true);
#NotNull
public final LiveData getSomeData() {
return (LiveData)this._someData;
}
}
Method B
class ThatViewModel : ViewModel() {
private val _someData = MutableLiveData(true)
val someData: LiveData<Boolean> = _someData
}
// Decompiled Kotlin bytecode
public final class ThatViewModelDecompiled extends ViewModel {
private final MutableLiveData _someData = new MutableLiveData(true);
#NotNull
private final LiveData someData;
#NotNull
public final LiveData getSomeData() {
return this.someData;
}
public ThatViewModel() {
this.someData = (LiveData)this._someData;
}
}
Is there a reason to use Method B over Method A?
From the Java perspective, Method A has one less field in the class, thus is "more" efficient. From the Kotlin perspective, Method B denotes a bit more clearly, that the non-mutable property is a direct reference to the mutable one. Also Kotlin is clever enough to locally access the field rather than the getter method.
Is there a reason to use Method B over Method A?
In general is merely a matter of taste. Looking at it from a micro-optimization perspective it depends on whether or not you'd also use this reference within the class itself.
Starting from Kotlin 1.4-M2 you can do simply:
private val myMutableLiveData = MutableLiveData<String>()
val myLiveData : LiveData<String> by this::myMutableLiveData
The this:: is unfortunately needed, otherwise does not compile.
I found this in Igor Wojda's answer which discusses other approaches. Unfortunately his answer in this question was deleted.
Consider the following ways to expose MutableLiveData:
Method A
class ThisViewModel : ViewModel() {
private val _someData = MutableLiveData(true)
val someData: LiveData<Boolean>
get() = _someData
}
// Decompiled Kotlin bytecode
public final class ThisViewModelDecompiled extends ViewModel {
private final MutableLiveData _someData = new MutableLiveData(true);
#NotNull
public final LiveData getSomeData() {
return (LiveData)this._someData;
}
}
Method B
class ThatViewModel : ViewModel() {
private val _someData = MutableLiveData(true)
val someData: LiveData<Boolean> = _someData
}
// Decompiled Kotlin bytecode
public final class ThatViewModelDecompiled extends ViewModel {
private final MutableLiveData _someData = new MutableLiveData(true);
#NotNull
private final LiveData someData;
#NotNull
public final LiveData getSomeData() {
return this.someData;
}
public ThatViewModel() {
this.someData = (LiveData)this._someData;
}
}
Is there a reason to use Method B over Method A?
From the Java perspective, Method A has one less field in the class, thus is "more" efficient. From the Kotlin perspective, Method B denotes a bit more clearly, that the non-mutable property is a direct reference to the mutable one. Also Kotlin is clever enough to locally access the field rather than the getter method.
Is there a reason to use Method B over Method A?
In general is merely a matter of taste. Looking at it from a micro-optimization perspective it depends on whether or not you'd also use this reference within the class itself.
Starting from Kotlin 1.4-M2 you can do simply:
private val myMutableLiveData = MutableLiveData<String>()
val myLiveData : LiveData<String> by this::myMutableLiveData
The this:: is unfortunately needed, otherwise does not compile.
I found this in Igor Wojda's answer which discusses other approaches. Unfortunately his answer in this question was deleted.
I've tried extracting the value into a base class and having the ViewModels extend it. When I do that, however, the Observer isn't sticking to the LiveData. For instance, when I have a parent class with LiveData:
class Base : ViewModel() {
private val _ data = MutableLiveData()
val data: LiveData = _data
fun someEvent(foo: Foo) { // update _data }
}
class Derived : Base()
class Derived1 : Base()
Then get one of those ViewModels and observe data:
class Frag : Fragment {
onViewCreated() {
// get Derived, ViewModelProviders.of ...etc
derived.data.observe { // Doesn't observe changes }
}
}
Calling Base.someEvent(foo) doesn't notify the LiveData in the Fragment.
I want to avoid getting a reference to both subclasses and invoking someEvent on each. One thing to note is that I'm using a single Activity approach and all ViewModels are Activity scoped.
class Derived : Base()
and
class Derived1 : Base()
have their own instance of:
private val _ data = MutableLiveData()
val data: LiveData = _data
that means you need to
derived.data.observe { // do something }
derived1.data.observer { // do something }
derived.someEvent(someFoo)
derived1.someEvent(someFoo)
You are trying to achieve something in a wrong way.