Why is the value param nullable in Observer from Android Architecture Components? - android

LiveData from architecture components defines an Observer with nullable value for the receiver callback:
public interface Observer<T> {
/**
* Called when the data is changed.
* #param t The new data
*/
void onChanged(#Nullable T t);
}
Why is there an explicitly nullable annotation?
The doc of LiveData.observe() also says:
If LiveData already has data set, it will be delivered to the observer.
E.g. Observer waits for non-nullable updates or immediately receive previous non-nullable value, that should hold especially in Kotlin, until I define T as nullable.
The code seem to be working like that. I understand why this doesn't hold for LiveData.getValue(), which may be called manually before first data is delivered (and checks therefore for mData != NOT_SET to return a null).
So the second question is: Is is safe to assume the value is non-null in Kotlin when T is non-nullable?

I think the fact that they made it Nullable is that they wanted to add the functionality for those who want to reset the liveData by nulling it's value. Also someone might want a nullable LiveData (and use that null in observe).
If you are creating/producing the LiveData, you could assume it is null (and use the !! operator) since a null would indicate an unexpected error. Also you could create a class like NonNullLiveData that ignores the values that are null in it's setValue. That way you could be sure that you never recieve nulls in your observe (although you can't make the #Nullable go away from the observer).

Fixed in androix.lifecycle 2.0.0-beta01.
Please report android Team if you encounter any issues.

Starting from 2.0.0-beta01 and later androidx.lifecycle version the onChangedparameter no longer contains #Nullable annotation. The changes is due to the improvement request courtesy by the OP.
package androidx.lifecycle;
/**
* A simple callback that can receive from {#link LiveData}.
*
* #param <T> The type of the parameter
*
* #see LiveData LiveData - for a usage description.
*/
public interface Observer<T> {
/**
* Called when the data is changed.
* #param t The new data
*/
void onChanged(T t);
}
Is is safe to assume the value is non-null in Kotlin when T is non-nullable?
It depends, if you're the one who created the LiveData subclass or plainly using the existing MutableLiveData and you design it that it will never return null then it is safe to assume that it will never return null.
For the case that the LiveData is implicitly created by not you especially those LiveData that are provided by Libraries, I would not assume it is non-null unless the library documentation mentioned it.

Related

What is the difference between LiveData<String>() and LiveData<String?>()

I am new to LiveData thing in general and I am having a hard time understanding the difference between LiveData<String>() and LiveData<String?>(). I used them interchangeably and nothing seams to break. I know that LiveData.getValue() is marked with #Nullable in Java, so we end up getting String? anyway. So what makes LiveData<String?>() different from LiveData<String>()?
This ended up a bit long but I hope it covers everything!
A LiveData is meant to be observed. The observer receives data, and the LiveData's type says what type that data is. A LiveData<String> will only supply non-null Strings to its observers. A LiveData<String?> can supply Strings and nulls.
Which of those you want depends on what you're doing! Do you need to supply nulls, e.g. for some kind of missing value or whatever? Should they be part of your data? If not, like in any other situation, avoid making the type nullable unless it needs to be.
When an observer first observes a LiveData, it receives the current value. That way it can immediately handle the current data, update to display the current state, etc. But it's possible for a LiveData to have no value initially:
// non-null
val liveDataWithValue = MutableLiveData<String>("hi")
val emptyLiveData = MutableLiveData<String>()
// nullable
val nullableLiveDataWithValue = MutableLiveData<String?>(null)
val emptyNullableLiveData = MutableLiveData<String?>()
The first one there has an initial value. If you observe it, and that value hasn't been updated, the observer will immediately be called with "hi" for its parameter.
The second one has no value. If you observe that, the observer won't be called until a value is set on it. This is useful when you don't actually have any initial data - you can still set up your observer, and nothing will happen until some data is actually pushed.
The third one is the same as the first - it's a nullable String? but with a value of null. That's still a value so if you observe it, the observer will immediately be called with that null. It's still a piece of data your observer has to react to and process.
The last one is nullable but with no initial value. Like the second one, this means there's nothing for the observer to receive at first - but when it does have a value set on it, it could be a null. null is just another kind of value!
But if you go poking around at the LiveData's value property, instead of interacting with it through observe, then that no value state is represented internally by null. Java (or at least the version Android targets) doesn't really have a representation of no value separate from null, so that's just how they have to do things. It just doesn't publish anything until you explicitly set a value on it.
So for each of these:
val emptyLiveData = MutableLiveData<String>()
val nullableLiveDataWithValue = MutableLiveData<String?>(null)
val emptyNullableLiveData = MutableLiveData<String?>()
if you read their value in this state, it will be null for all of them. One explicitly has a value of null set on it, the others are both empty. This also means that even though emptyLiveData's type is non-null, its value property can be null, just because of this "can be empty" situation which is true for all LiveData objects. The nullability of the type is purely about what gets passed to observers.
You generally shouldn't be reading value anyway, except internally (wherever you're actually setting the value). Everything else should be interacting with that LiveData by observing it and reacting to the values that are published, and those values will be whatever type (nullable or not) that you specified
LiveData<String?>() meens that livedata can store null, read please this article to be fully informed: https://kotlinlang.org/docs/null-safety.html

Retrieving latest value of a Flow which is not a StateFlow

How can I get the latest value of a Flow? I don't have a StateFlow where I need that latest value. This is the condensed scenario:
There is a repository exposing a StateFlow
val repositoryExposedStateFlow: StateFlow<SomeType> = MutableStateFlow(...)
Additionally there are mappers transforming that StateFlow like
val mappedFlow: Flow<SomeOtherType> = repositoryExposedStateFlow.flatMapLatest { ... }
mappedFlow is no StateFlow anymore, but just a Flow. Thus, I cannot get the latest/current value as I can when there's StateFlow.
Anyhow, I need the latest value in that Flow at some point. Since this point is not in a ViewModel, but some Use Case implementation, I cannot simply perform a stateIn and hold the latest value in the ViewModel all the time the ViewModel is alive -- otherwise I had to pass on the value to all Use Cases. Actually, within a Use Case I trigger a network refresh which leads to emitting of new values on the StateFlow and thus on the mappedFlow, too.
In the Use Cases I have CoroutineScopes though. So I came up with
suspend fun <T> Flow<T>.getState(): T {
return coroutineScope {
val result = stateIn(
scope = this
).value
coroutineContext.cancelChildren()
result
}
}
Without using coroutineContext.cancelChildren() the method will never return, because coroutineScope blocks the caller until all child coroutines have finished. As stateIn never finishes, I manually cancel all children.
Apparently this is a bad thing to do.
But how can I solve this problem in a better way? In my perception the problem arises from StateFlow mapping resulting in regular Flow instances.
Yes, all you need is to call first() on the flow. Since it is backed by a StateFlow upstream, the first() call will get the current value of that backing StateFlow, run it through whatever transformations happen from the downstream operators, and return that value.
This effectively gets you the same result as your attempt above.
The downside is that all the downstream operators must be run, so it is potentially expensive.
This is only possible if there is an upstream StateFlow. Otherwise, there is no concept of a latest value for you to be able to retrieve.
I would challenge your need to get the latest value, though. Typically, you collect flows, so you're already working with a current value. Flows are intended for reactive programming.

What does relaxed = true do in mockK?

I read document, but I don't still get it.
The differences between this
private val myClass: MyClass = mockk(relaxed = true)
and this.
private val myClass: MyClass = mockk()
What I understood is if relaxed is true. Then, all the member fields or methods will return default values. Otherwise, not. is that correct understanding?
If so, setting always relaxed = true is better. But In this video, Ryan uses both. why?
https://youtu.be/60KFJTb_HwU?t=1015
If you're trying to call a mock method that doesn't know what to return and relaxed is not set to true you'll get an exception thrown. This is made, so tests are less likely to introduce unpredictable behavior, due to the default values returned by methods that the developer does not purposely mock.
In the linked video the view methods are probably never called, therefore no "relaxed" is necessary. You can also use "relaxedUnitFun", which works only for methods returning Unit, handy for example for classes responsible for events logging.
This is a double-edged weapon though, as "relaxing" everything deprives you of the security mechanism mentioned above. If this is what you want, you can also configure this globally, check https://mockk.io/#settings-file
To quote their documentation:
A relaxed mock is the mock that returns some simple value for all functions. This allows you to skip specifying behavior for each case, while still stubbing things you need. For reference types, chained mocks are returned.
source

Difference of setValue() & postValue() in MutableLiveData

There are two ways that make change value of MutableLiveData. But what is difference between setValue() & postValue() in MutableLiveData.
I could not find documentation for same.
Here is class MutableLiveData of Android.
package android.arch.lifecycle;
/**
* {#link LiveData} which publicly exposes {#link #setValue(T)} and {#link #postValue(T)} method.
*
* #param <T> The type of data hold by this instance
*/
#SuppressWarnings("WeakerAccess")
public class MutableLiveData<T> extends LiveData<T> {
#Override
public void postValue(T value) {
super.postValue(value);
}
#Override
public void setValue(T value) {
super.setValue(value);
}
}
Based on the documentation:
setValue():
Sets the value. If there are active observers, the value will be
dispatched to them. This method must be called from the main thread.
postValue():
Posts a task to a main thread to set the given value. If you called this method multiple times before a main thread executed a posted task, only the last value would be dispatched.
To summarize, the key difference would be:
setValue() method must be called from the main thread. But if you need set a value from a background thread, postValue() should be used.
All of the above answers are correct. But one more important difference. If you call postValue() and after that you call getValue(), you may not receive the value that you set in postValue(). If the main thread had already set the value, then you will get the value that you posted, but if the main thread hadn't set the value yet, then you don't get the value that you posted. So be careful if you work in background threads.
setValue() is called directly from caller thread, synchronously notifies observers and changes LiveData value immediately. It can be called only from MainThread.
postValue() uses inside something like this new Handler(Looper.mainLooper()).post(() -> setValue()), so it runs setValue via Handler in MainThread. It can be called from any thread.
setValue()
Sets the value. If there are active observers, the value will be dispatched to them.
This method must be called from the main thread.
postValue
If you need set a value from a background thread, you can use postValue(Object)
Posts a task to a main thread to set the given value.
If you called this method multiple times before a main thread executed a posted task, only the last value would be dispatched.
This is not a direct answer to the above problem. The answers from Sagar and w201 are awesome. But a simple rule of thumb I use in ViewModels for MutableLiveData is:
private boolean isMainThread() {
return Looper.myLooper() == Looper.getMainLooper();
}
private MutableLiveData<Boolean> mutVal = new MutableLiveData<>(false);
public LiveData<Boolean> getMutVal() { return this.mutVal; }
public void setMutVal(boolean val) {
if (isMainThread()) mutVal.setValue(val);
else mutVal.postValue(val);
}
Replace mutVal with your desired value.
setValue() method must be called from the main thread. If you need to set a value from a background thread, you can use postValue().
More here.
postValue - can be used from anywhere
setValue - only from main/UI thread
Basically, postValue should be used only from background thread as it might be slower compared to setValue, which reacts faster.
I've wrote a snippet that handles both case:
/**
* Live data thread-safe set-value
* Context: https://stackoverflow.com/a/52227632/6688493
*/
fun <T> MutableLiveData<T>.assignValue(newValue: T){
if(Looper.myLooper() == Looper.getMainLooper()) {
this.value = newValue
}
else {
this.postValue(newValue)
}
}
TL; DR
If you are working on the main thread, then both setValue and postValue will work in the same manner i.e. they will update the value and notify the observers.
If working in some background thread, then you can't use setValue. You have to use postValue here with some observer.
More here
In our app, we had used single LiveData that contains data for multiple views in an activity/screen. Basically N no of datasets for N no of views. This troubled us a bit because the way postData is designed for. And we have state object in LD that conveys to view about which view needs to be updated.
so LD looks like this:
LD {
state (view_1, view_2, view_3 …),
model_that_contains_data_of_all_views
}
There are couple of views (view_1 and view_2) that had to be updated when one event occurs..mean they should get notified at the same time when event occurs. So, I called:
postData(LD(view_1, data))
postData(LD(view_2, data)
This would not work for reasons we know.
What I understood is that basically one LD should represent only one view. Then there is no chance that you would've to call postData() twice in a row. Even if you call, the way postData handles it for you is what you would also expect (showing latest data for you in view). Everything fall well in place.
One LD -> one View. PERFECT
One LD -> multiple views THERE MAY BE A WEIRD BEHAVIOR
If setting the value will take a long time (if you have to retrieve additional data from a remote source that could be slow to respond, for example), use postValue() so you don't lock up the main thread.
When setting the value is guaranteed to be fast (as it most often is), setValue() is simplest and best.

Checking if RoomDatabase is empty while using LiveData

I am trying to use RoomDatabase in my Android App. And I am using LiveData to be able to refresh my changes automatically inside my fragment.
The first time I am running my app I am getting the data from the API, creating my RoomDatabase and storing my data.
The second time I run my app I want to check if my DataBase is not empty. But while using LiveData: the following code is returning null.
AppDatabase.getInstance(getContext()).getRecipeDao().getAllRecipes().getValue();
I have read that "if the response is an observable data type, such as Flowable or LiveData, Room watches all tables referenced in the query for invalidation".
How to check if my RoomDatabase has data or is empty?
So after implementing myself I found that you need to do a few things:
Make sure you have an Observer for changes to the LiveData
You need to call observeForever(Observer<T> observer) unless you are using a LiveCyclerOwner then use that instead with: observe (LifecycleOwner owner, Observer<T> observer)
Finally, there is an interesting note on getValue():
Returns the current value. Note that calling this method on a
background thread does not guarantee that the latest value set will be
received
So to reiterate, I think your approach does not work.
You will need to create some type of separate check rather than use a method that returns a LiveData class as noted since it does not guarantee the latest value set is received by calling getValue().
I would recommend something super simple in the end such as adding a new method to your Dao
#Query("SELECT * FROM recipes LIMIT 1")
Recipe getAnyRecipe();
and do this check looking for null to see if anything exists in the recipes table.

Categories

Resources