Recently, I am stuck with the following code.
public class NoteViewModel extends ViewModel {
private final MutableLiveData<List<Note>> notesLiveData = new MutableLiveData<>();
public NoteViewModel() {
LiveData<List<Note>> notesLiveDataFromRepository = NoteRepository.INSTANCE.getNotes();
// How can I "assign" LiveData from Room, to MutableLiveData?
}
}
I was wondering, how can I "assign" LiveData
from Room
, to MutableLiveData
?
Using Transformation.map
and Transformation.switchMap
wouldn't work, as both returns LiveData
, not MutableLiveData
.
One of the possible solution is that, instead of
@Dao
public abstract class NoteDao {
@Transaction
@Query("SELECT * FROM plain_note")
public abstract LiveData<List<Note>> getNotes();
I will use
@Dao
public abstract class NoteDao {
@Transaction
@Query("SELECT * FROM plain_note")
public abstract List<Note> getNotes();
Then, in my ViewModel
, I will write
public class NoteViewModel extends ViewModel {
private final MutableLiveData<List<Note>> notesLiveData = new MutableLiveData<>();
public NoteViewModel() {
new Thread(() -> {
List<Note> notesLiveDataFromRepository = NoteRepository.INSTANCE.getNotes();
notesLiveData.postValue(notesLiveDataFromRepository);
}).start();
}
}
I don't really like this approach, as I'm forced to handle threading thingy explicitly.
Is there a better way, to avoid handling threading explicitly?
Use LiveData for the app's data (word, word count and the score) in the Unscramble app. Add observer methods that get notified when the data changes, update the scrambled word text view automatically. Write binding expressions in the layout file, which are triggered when the underlying LiveData is changed.
By using LiveData we can only observe the data and cannot set the data. MutableLiveData is mutable and is a subclass of LiveData. In MutableLiveData we can observe and set the values using postValue() and setValue() methods (the former being thread-safe) so that we can dispatch values to any live or active observers.
So, LiveData is immutable. MutableLiveData is LiveData which is mutable & thread-safe.
The trick is to not do any of the actual fetching in the view model.
Getting data, be it from network or database, should be done in the repository. The ViewModel should be agnostic in this regard.
In the ViewModel, use the LiveData class, not MutableLiveData. Unless you really find a use case for it.
// In your constructor, no extra thread
notesLiveData = notesLiveDataFromRepository.getAllNotes();
Then in your repository you can have the logic in the getAllNotes() method for determining where those notes are coming from. In the repository you have the MutableLiveData. You can then postValue to that, from a thread that is getting the data. That isn't necessary for room though, that is handled for you.
So in your repository you would have another LiveData being returned that is backed directly from a DAO method.
In that case, you need to stick with public abstract LiveData<List<Note>> getNotes();
.
public class MyActivity extends AppCompatActivity {
private MyViewModel viewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Set up your view model
viewModel = ViewModelProviders.of(this).get(MyViewModel.class);
// Observe the view model
viewModel.getMyLiveData().observe(this, s -> {
// You work with the data provided through the view model here.
// You should only really be delivering UI updates at this point. Updating
// a RecyclerView for example.
Log.v("LIVEDATA", "The livedata changed: "+s);
});
// This will start the off-the-UI-thread work that we want to perform.
MyRepository.getInstance().doSomeStuff();
}
}
public class MyViewModel extends AndroidViewModel {
@NonNull
private MyRepository repo = MyRepository.getInstance();
@NonNull
private LiveData<String> myLiveData;
public MyViewModel(@NonNull Application application) {
super(application);
// The local live data needs to reference the repository live data
myLiveData = repo.getMyLiveData();
}
@NonNull
public LiveData<String> getMyLiveData() {
return myLiveData;
}
}
public class MyRepository {
private static MyRepository instance;
// Note the use of MutableLiveData, this allows changes to be made
@NonNull
private MutableLiveData<String> myLiveData = new MutableLiveData<>();
public static MyRepository getInstance() {
if(instance == null) {
synchronized (MyRepository.class) {
if(instance == null) {
instance = new MyRepository();
}
}
}
return instance;
}
// The getter upcasts to LiveData, this ensures that only the repository can cause a change
@NonNull
public LiveData<String> getMyLiveData() {
return myLiveData;
}
// This method runs some work for 3 seconds. It then posts a status update to the live data.
// This would effectively be the "doInBackground" method from AsyncTask.
public void doSomeStuff() {
new Thread(() -> {
try {
Thread.sleep(3000);
} catch (InterruptedException ignored) {
}
myLiveData.postValue("Updated time: "+System.currentTimeMillis());
}).start();
}
}
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