Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get one value from LiveData

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.

like image 693
Tom11 Avatar asked Apr 13 '19 14:04

Tom11


People also ask

What is single live event?

SingleLiveEvent is a subclass of MutableLiveData with a single Observer Observing it at a time, hence it is aware of view's lifecycle.

How do you observe a LiveData?

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.

Is flow better than LiveData?

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.

Can LiveData values be null?

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.


1 Answers

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:

  • get the current books list
  • then calculate bookMax
  • then actually insert.
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);
like image 140
dhabensky Avatar answered Sep 30 '22 11:09

dhabensky