【发布时间】:2021-07-21 11:06:07
【问题描述】:
由于不推荐使用 AsyncTask() 方法,我正在尝试替换它。以前 AsyncTask() 用于将 CardViews 从 Room 数据库加载到 RecyclerView 列表中。我正在尝试使用 CompletableFuture() 作为替代,但列表未加载。 “List getAllCards()”的 Dao 方法在 Android Studio 中给出错误消息“从不使用该方法的返回值”,因此听起来列表从未从数据库中获取。 Repository 从 ViewModel 中获取 List 方法,ViewModel 在 MainActivity 中获取 List 方法调用。
我还想避免“ExecutorService.submit(() - > cardDao()).get()”加载列表,因为它是阻塞的。我在下面展示了运行良好的 ExecutorService submit(() 方法,以供参考。
由于列表未加载,我在这里缺少什么?
Repository
public List<Card> getAllCards() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
CompletableFuture.supplyAsync(() -> {
List<Card> loadAllCards = new ArrayList<>();
cardDao.getAllCards();
return loadAllCards;
}).thenAcceptAsync(loadAllCards -> getAllCards());
}
return null;
}
Dao
@Dao
public interface QuickcardDao {
@Query("SELECT * FROM cards ORDER BY Sortorder DESC")
List<Card> getAllCards();
}
这是我要替换的存储库中的 AsyncTask():
public CardRepository(Application application) {
CardRoomDatabase db = CardRoomDatabase.getDatabase(application);
cardDao = db.cardDao();
}
public List<Card> getAllCards() {
try {
return new AllCardsAsyncTask(cardDao).execute().get();
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
}
return null;
}
// AsyncTask for reading an existing CardViews from the Room database.
private static class AllCardsAsyncTask extends AsyncTask<Void, Void, List<Card>> {
private CardDao cardDao;
AllCardsAsyncTask(CardDao dao) {
cardDao = dao;
}
@Override
public List<Card> doInBackground(Void... voids) {
return cardDao.getAllCards();
}
}
这是我要替换的存储库中的 submit(() 方法:
public List<Card> getAllCards() {
List<Card> newAllCards = null;
try {
newAllCards = CardRoomDatabase.databaseExecutor.submit(() -> cardDao.getAllCards()).get();
}
catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
return newAllCards;
}
// 结束
【问题讨论】:
-
即使在您的旧代码中也存在一个根本问题。你正在创建一个异步任务,但立即等待它的结果,所以这就像根本不是异步的。你仍然在阻塞调用者的线程。您必须将逻辑更改为“生成一个异步任务”,“告诉它完成后要做什么”。您不能在必须将结果返回给调用者的方法中进行异步操作。
-
@Holger 明白了。那么 CompletableFuture 在这方面没有帮助吗,因为如果使用 thenApply Async() 将 List 加载到 UI,它只会在完成时提供结果?这样就避免了返回空列表的问题(你在这里提到:stackoverflow.com/questions/43489281/…)?
-
其他问题的问题对您没有影响。那是关于真正尽早返回列表,同时仍在另一个线程中向其中添加元素。您的问题是关于对
cardDao.getAllCards()的一次调用,它确实已经返回了一个完全填充的列表(我希望如此)。这就是为什么你不能提前返回结果。您只能等待结果(阻塞调用者线程)或不返回结果(但如果您愿意,可以返回未来)并通过告诉结果可用时做什么来实现异步行为。 -
喜欢
CompletableFuture.supplyAsync(cardDao::getAllCards) .thenApply(result -> someMethod(result))。请注意,大多数 UI 框架都需要在专用 UI 线程中进行 UI 修改。使用 AWT/Swing,您必须使用CompletableFuture.supplyAsync(cardDao::getAllCards) .thenApplyAsync(result -> someMethod(result), EventQueue::invokeLater)在事件调度线程中强制执行结果消费。我想,Android 也有类似的结构。 -
如果适合您,我可以使用 RxJava 或 KotlinCoroutines 为您提供完全异步的代码。
标签: android android-asynctask android-room completable-future