我有Simple DAO包括CRUD功能
FeedEntryDAO.java
@Dao
public interface FeedEntryDAO {
@Query("SELECT * FROM feedEntrys")
LiveData<List<FeedEntry>> getAll();
@Query("SELECT * FROM feedEntrys WHERE uid = :uid LIMIT 1")
LiveData<FeedEntry> findByUid(int uid);
@Insert
void insertAll(FeedEntry... feedEntries);
@Delete
void delete(FeedEntry feedEntry);
@Update
int update(FeedEntry feedEntry);
}
对于select
,可以返回LiveData类型。
在Activity中,代码非常适合选择
viewModel.getFeedEntrys().observe(this,entries -> {...});
但是,当我尝试插入,更新,删除数据时。代码看起来有点难看,每次都会创建一个asynctask。
new AsyncTask<FeedEntry, Void, Void>() {
@Override
protected Void doInBackground(FeedEntry... feedEntries) {
viewModel.update(feedEntries[0]);
return null;
}
}.execute(feedEntry);
我有2个问题:
感谢任何建议和建议。谢谢。
答案 0 :(得分:5)
- 我可以使用LiveData来包装删除,插入,更新通话吗?
醇>
不,你不能。我写了issue的答案。原因是,LiveData用于通知更改。插入,更新,删除不会触发更改。它将返回已删除的行,插入的ID或受影响的行。即使它看起来很糟糕也没有意义,没有LiveData包裹你的东西。无论如何,在调用之间使用Single这样的东西是有意义的,让操作在RX-Java操作上触发和操作。
如果您想触发这些调用,您可以在选择查询中观察,该查询会通知您已更新,插入或删除某些/任何数据的LiveData。
- 更好的方法来维护这样的asynctask类用于删除,插入,更新?
醇>
在查看您的示例后,您似乎滥用了(模型/视图/)ViewModel-Pattern。您永远不应该在视图中访问您的存储库。我不确定你是否这样做,因为它在你的样本中不可见。无论如何,在观察LiveData并获得结果之后,无需在viewModel中将数据更新包装在AsyncTask中。这意味着,你应该总是照顾
a)查看&lt; - &gt; viewmodel&lt; - &gt;存储库而不是视图&lt; - &gt;存储库和视图&lt; - &gt;视图模型
和
b)不要尝试使用不需要的线程。您默认情况下在后台线程(@WorkerThread)上观察LiveData(如果没有使用@MainThread注释)并在ui-thread中获取值(@MainThread)。答案 1 :(得分:3)
要解决您的第二个问题:
Google发布了一个Android Room Codelab here,其中列出了用于在Android中实现Room的简洁MVVM体系结构:
此处建议由Database类中的公共静态ExecutorService处理数据库操作。 ExecutorService类的位置可能有所不同,只要记住这个想法是在MVVM中,您的视图就不关心实际CURD处理数据的方式,这是ViewModel而不是View 的责任。
github repository for this code lab
简而言之,要将类似的想法应用到您的代码中,就像这样:
class YourRepository {
private FeedEntryDAO mFeedEntryDAO;
YourRepository(Application application) {
YourDatabase db = YourDatabase.getDatabase(application);
mFeedEntryDAO = db.feedEntryDAO();
mAllWords = mWordDao.getAlphabetizedWords();
}
void update(FeedEntry feedEntry) {
Database.databaseExecutor.execute(() - > {
mFeedEntryDAO.update(feedEntry);
});
}
}
class YourViewModel extends ViewModel {
private YourRepository mRepository;
void update(FeedEntry feedEntry) {
mRepository.update(feedEntry)
}
}
这样做,您的View可以直接调用viewModel.update(feedEntries [0])。
要提及的一件事是 mFeedEntryDAO.update(feedEntry)将自动触发getFeedEntrys LiveData上的观察者的onChanged回调。
这对您来说很方便。您可以了解有关触发如何发生的更多信息here。
答案 2 :(得分:1)
对于第二个问题,AsyncTask还有另一个更巧妙的选择;使用Java Executor
的人来说,好消息是您可以对所有CRUD操作使用Executor
的单个实例,而不是AsyncTask
的多个实例。
演示示例
public class Repository {
private static Repository instance;
private MyDatabase mDatabase;
private Executor mExecutor = Executors.newSingleThreadExecutor();
private Repository(Application application) {
mDatabase = MyDatabase.getInstance(application.getApplicationContext());
}
public static Repository getInstance(Application application) {
if (instance == null) {
instance = new Repository(application);
}
return instance;
}
public void insert(final MyModel model) {
mExecutor.execute(new Runnable() {
@Override
public void run() {
mDatabase.getMyModelDAO().insert(model);
}
});
}
public void update(final MyModel model) {
mExecutor.execute(new Runnable() {
@Override
public void run() {
mDatabase.getMyModelDAO().update(model);
}
});
}
public void delete(final MyModel model) {
mExecutor.execute(new Runnable() {
@Override
public void run() {
mDatabase.getMyModelDAO().delete(model);
}
});
}
}
答案 3 :(得分:1)
关于问题2:
对于Kotlin用户,现在有一种非常好的方法来实现这一目标, 因为自2.1室以来,直接支持协程。给出了一个整洁的示例here。
您可以直接在DAO中使用“暂停功能”,该操作可避免在主线程上执行任何操作:
@Dao
interface BarDao {
@Query("SELECT * FROM bar WHERE groupId = 2")
fun getAllBars(): LiveData<MutableList<Bar>>
@Query( "SELECT * FROM bar WHERE groupId = 0 LIMIT 1")
fun getRecentBar(): LiveData<Bar>
@Insert
suspend fun insert(bar: Bar)
@Update
suspend fun update(bar: Bar)
@Delete
suspend fun delete(bar: Bar)
}
然后在您的viewModel中,您将:
fun insert(bar: Bar) = viewModelScope.launch {
barDao.insert(bar)
}
fun update(bar: Bar) = viewModelScope.launch {
barDao.update(bar)
}
fun delete(bar: Bar)= viewModelScope.launch {
barDao.delete(bar)
}
答案 4 :(得分:1)
列出了每个受支持库的受支持返回类型here。为方便起见,我将表格包含在此处。
查询类型 | Kotlin 语言特性 | RxJava | 番石榴 | Jetpack 生命周期 |
---|---|---|---|---|
一次性写入 | 协程 (orgUnitPath: getOrgUnitPath(accountType, formObject.accountType),
) |
suspend 、Single<T> 、Maybe<T> |
Completable |
不适用 |
一次性阅读 | 协程 (ListenableFuture<T> ) |
suspend , Single<T> |
Maybe<T> |
不适用 |
可观察读取 | ListenableFuture<T> |
Flow<T> 、Flowable<T> 、Publisher<T> |
不适用 | Observable<T> |
答案 5 :(得分:0)
您也可以在抽象类中使用@Dao批注,因此:
@Dao BaseDao
和具体方法@Insert insert(entities)
创建一个抽象insert(entities, callback)
类,该类执行难看的AsyncTask
工作,调用抽象@Insert insert(entities)
在onBackground
上,您的回调在onPostExecute
上。FeedEntryDAO
也抽象化扩展BaseDao
和@Query
方法抽象化。Kotlin中的结果用法很漂亮:
database.entityDao().insert(entities) { ids ->
// success
}
答案 6 :(得分:0)
要使应用程序的UI在数据更改时自动更新,请在查询方法说明中使用LiveData类型的返回值。更新数据库后,Room会生成所有必需的代码来更新LiveData。
pageant
注意:从1.0版开始,Room使用在 查询以决定是否更新LiveData实例。