I have LiveData
for Books in ViewModel
's constructor:
LiveData<List<Book>> books;
public MyViewModel(@NonNull Application application) {
super(application);
books = bookRepository.getBooks();
}
When user creates new book
from UI, I want attribute book_order
to be filled with incremented maximum of book_order
of other books. To better describe what I want, see following preudocode:
book.book_order = max(books.book_order) + 1;
So when there are three books with book_order
1, 2, 3 respectively, new book would have this attribute set to 4.
Question is, how can I do this with LiveData
in ViewModel
? I tried using Transformations.map
to the new LiveData
, but this approach is not working at all, bookMax
seems to be null
.
public void insertBook(Book book) {
LiveData<Integer> bookMax = Transformations.map(books,
list -> {
int value = 0;
for(Book b: list) {
if (value < b.getBookOrder()) {
value = b.getBookOrder();
}
}
}
);
book.setBookOrder(bookMax + 1)
bookRepository.update(book);
}
Any ideas how to set incremented maximum to the new book? It can be another approach than the one described here. ViewModel
was created to separate app logic from UI. However it does not seem to do that in this case, because if I want to observe value, I need to be in Activity
. Also, I did not find any alternative how to do this kind of getting one value from DB. Any help appreciated.
SingleLiveEvent is a subclass of MutableLiveData with a single Observer Observing it at a time, hence it is aware of view's lifecycle.
You usually create an Observer object in a UI controller, such as an activity or fragment. Attach the Observer object to the LiveData object using the observe() method. The observe() method takes a LifecycleOwner object. This subscribes the Observer object to the LiveData object so that it is notified of changes.
StateFlow and LiveData have similarities. Both are observable data holder classes, and both follow a similar pattern when used in your app architecture. The StateFlow and LiveData do behave differently: StateFlow requires an initial state to be passed into the constructor, while LiveData does not.
This is an error, and is also enforced at build time when supported by the build system. For Android this means it will run during release builds. This check ensures that LiveData values are not null when explicitly declared as non-nullable.
Note that your books
are livedata
, thus may change its value from time to time.
Whereis your bookMax
is a single value that should be calculated at the moment of insertion.
To insert you need:
val bookList: List<Book> = books.value // current value. may be null!
val bookMax: Int = bookList.maxBy { it.order }.order // find max order
// insert
val newBooks = arrayListOf(bookList)
newBooks.add(newBook)
books.value = newBooks // update your livedata
EDIT Here is Java code
// get current value. may be null!
List<Book> bookList = books.getValue();
// so we better handle it early
if (bookList == null) {
bookList = new ArrayList<>();
}
// calculate max order
int maxOrder = -1;
for (Book book : bookList) {
if (maxOrder < book.order) {
maxOrder = book.order;
}
}
// create new book
Book newBook = new Book();
newBook.order = maxOrder + 1;
// add book to the list
bookList.add(newBook);
// do with new list whatever you want
// for example, you can update live data (if it is a MutableLiveData)
books.setValue(bookList);
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