我在LiveData
的构造函数中拥有ViewModel
的图书:
LiveData<List<Book>> books;
public MyViewModel(@NonNull Application application) {
super(application);
books = bookRepository.getBooks();
}
当用户从用户界面创建新的book
时,我希望属性book_order
被其他书籍中book_order
的最大增量填充。为了更好地描述我想要的内容,请参见以下preudocode:
book.book_order = max(books.book_order) + 1;
因此,当三本书分别具有book_order
1、2、3时,新书的此属性将设置为4。
问题是,我该如何使用LiveData
中的ViewModel
?我尝试对新的Transformations.map
使用LiveData
,但是这种方法根本不起作用,bookMax
似乎是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);
}
任何想法如何为新书设置递增的最大值?这可能是不同于此处描述的另一种方法。 ViewModel
的创建是为了将应用程序逻辑与UI分开。但是,在这种情况下似乎并没有这样做,因为如果我想观察价值,就需要进入Activity
。此外,我没有找到其他选择方法来实现这种从DB获得价值的方法。任何帮助表示赞赏。
答案 0 :(得分:0)
请注意,您的books
是livedata
,因此可能会随时更改其值。
您的bookMax
是一个单个值,应在插入时进行计算。
要插入,您需要:
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
编辑这是Java代码
// 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);
答案 1 :(得分:0)
在您的情况下使用LiveData将无济于事。
DAO中的LiveData在另一个线程上执行,新值发布在观察者代码中,或者在您的情况下,在Transformation.map()回调中发布。因此,您需要在Transformation.map()中访问book.id。
但是,如果将book插入Transformation.map(),则会触发无限循环,因为在每个表条目更新上,都会调用Transformation.map(),因为LiveData>会发生变化。
因此,对于您的情况:
答案 2 :(得分:0)
您应该在存储库中建立一个方法,该方法将为您提供最大数量的book_order
,而不是从数据库中查找最大的书本订单。
类似于下面的伪代码:
int maxOrder = bookRepository.getMaxBookOrder();
现在,您所要做的就是插入新书时,您可以使用该maxOrder
变量来达到增量目的。
因此,您的插入方法将类似于:
public void insertBook(Book book) {
int maxOrder = bookRepository.getMaxBookOrder();
book.setBookOrder(maxOrder + 1)
bookRepository.update(book);
}
在这里,假设您使用ROOM来存储持久数据库,那么此查询可以帮助您获得最大的book_order
:
SELECT MAX(book_order) FROM Book
如果您不喜欢ROOM,则可以使用另一种方法:
我们首先使用存储库方法检索列表,然后从伪列表中找到最大值,如下所示:
List<Book> books = bookRepository.getBooks().getValue(); // Assuming getBooks() returns LiveData
然后从中找到最大值,然后将其递增一:
public void insertBook(Book book) {
List<Book> books = bookRepository.getBooks().getValue();
// calculating max order using loop
int maxOrder = -1;
for (Book book : books) {
if (maxOrder < book.order) {
maxOrder = book.order;
}
}
book.setBookOrder(maxOrder + 1)
bookRepository.update(book);
}
即使您可以像上面提到的那样将查找最大值的代码移至存储库方法,如:
public int getMaxBookOrder() {
List<Book> books = getBooks().getValue();
// calculating max order using loop
int maxOrder = -1;
for (Book book : books) {
if (maxOrder < book.order) {
maxOrder = book.order;
}
}
return maxOrder;
}
答案 3 :(得分:0)
如果您真的想用LiveData
来做,可以创建一个自定义的:
class BooksLiveData(list: List<Book>) : LiveData<List<Book>>() {
val initialList: MutableList<Book> = list.toMutableList()
fun addBook(book: Book) {
with(initialList) {
// Assuming your list is ordered
add(book.copy(last().bookOrder + 1))
}
postValue(initialList)
}
}
然后您可以创建它并使用:
val data = bookRepository.getBooks() // Make getBooks() return BooksLiveData now
data.addBook(userCreatedBook) // This'll trigger observers as well
您仍然可以观察此实时数据,因为添加书后它会发布initialList
,它将通知观察者。您可以对其进行更多更改,例如退回已添加的书等。
旁注:最好从MutableLiveData
扩展,因为LiveData
不应更新其值,但是在内部您正在发布内容,因此令人困惑。
答案 4 :(得分:0)
方法1:
您可以将自动递增字段或PrimaryKey
之类的id
用于book_order
的功能。如果愿意,您甚至可以将其命名为book_order
。使您的Model或Entity类如下:
public class Book{
@PrimaryKey(autoGenerate = true)
private int book_order;
//other data members, constructors and methods
}
因此,book_order
在添加到数据库中的每个Book
时递增。
接下来,您可以像ViewModel
这样的课程:
public class MyViewModel extends AndroidViewModel {
private BookRepository bookRepository;
LiveData<List<Book>> books;
public MyViewModel(@NonNull Application application) {
super(application);
bookRepository = AppRepository.getInstance(application.getApplicationContext());
books = bookRepository.getBooks();
}
}
现在,您可以通过将对以下方法的调用放在您活动的onCreate()
中来为该ViewModel订阅活动列表(即使您的活动遵守ViewModel):
private void initViewModel() {
final Observer<List<Book>> bookObserver= new Observer<List<Book>>() {
@Override
public void onChanged(@Nullable List<Book> books) {
bookList.clear();
bookList.addAll(books);
if (mAdapter == null) {
mAdapter = new BooksAdapter(bookList, YourActivity.this);
mRecyclerView.setAdapter(mAdapter);
} else {
mAdapter.notifyDataSetChanged();
}
}
};
mViewModel = ViewModelProviders.of(this)
.get(MyViewModel.class);
mViewModel.mBooks.observe(this, notesObserver); //mBooks is member variable in ViewModel class
}
执行这些操作,您将能够接收更新,即。每当用户将Book
添加到数据库时,“列表/回收者”视图应自动显示新添加的Book
。
方法2:
如果这根本不是您想要的,而您只想查找最新添加的书籍的顺序,则可以完全跳过第三个代码块,并在Dao
中使用以下代码:
@Query("SELECT COUNT(*) FROM books")
int getCount();
给出书的总数,即图书表中的行,然后您可以从存储库中调用这些行,而存储库又可以从ViewModel中调用它,而ViewModel可以从Activity中调用。
方法3:
如果您想要book_order
(我认为这是添加新书后数据库中最新的书数),则可以使用方法1,该方法在ViewModel中为您提供书目列表。然后,您可以从书单计数中获取书数。
重要!
您想在编辑器或newBook ViewModel中编辑insertBook()
方法的任何一种,并使其类似于:
public void insertBook(Book book) {
Book book= mLiveBook.getValue(); //declare mLiveBook as MutableLiveData<Book> in this ViewModel
//maybe put some validation here or some other logic
mRepository.insertBook(book);
}
,在您的存储库中,相应的插入应如下所示:
public void insertBook(final Book book) {
executor.execute(new Runnable() {
@Override
public void run() {
mDb.bookDao().insertBook(book);
}
});
}
以及相应的Dao方法:
@Insert(onConflict = OnConflictStrategy.REPLACE)
void insertBook(Book book);