【问题标题】:android: load List from Room using CompletableFuture?android:使用 CompletableFuture 从 Room 加载列表?
【发布时间】: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 -&gt; someMethod(result))。请注意,大多数 UI 框架都需要在专用 UI​​ 线程中进行 UI 修改。使用 AWT/Swing,您必须使用 CompletableFuture.supplyAsync(cardDao::getAllCards) .thenApplyAsync(result -&gt; someMethod(result), EventQueue::invokeLater) 在事件调度线程中强制执行结果消费。我想,Android 也有类似的结构。
  • 如果适合您,我可以使用 RxJava 或 KotlinCoroutines 为您提供完全异步的代码。

标签: android android-asynctask android-room completable-future


【解决方案1】:

既然你说你不想使用RxJavacoroutines 并且我不熟悉CompletableFuture 我想建议你从数据库中获取数据而不阻塞UI thread 的最简单方法 -使用LiveDataLiveData 默认在一个单独的线程上执行 fetch 操作,然后通知所有的观察者。

以下是必要的步骤:

  1. 将此依赖添加到 gradle

    implementation "androidx.lifecycle:lifecycle-livedata:2.3.1"

  2. 摆脱所有与 Asynctask 或 CompletableFuture 相关的代码


  1. 将如下方法添加到 @Dao 带注释的类中

     @Dao
     public interface QuickcardDao {
    
     @Query("SELECT * FROM cards ORDER BY Sortorder DESC")
     LiveData<List<Card>> getAllCards();}
    

  1. 将方法添加到您的回购中,如下所示

    public LiveData<List<Card>> getAllCards() {
            return cardDao.getAllCards();   
         }
    

  1. 将方法添加到您的 ViewModel,如下所示:

    public LiveData&lt;List&lt;Card&gt;&gt; getAllCardsLive{ return repo.getAllCards(); }


  1. 在你的活动中观察LiveData

    `viewModel.getAllCardsLive().observe(getViewLifeycleOwner(), cards ->{
         // submit obtained cards lit to your adapter
     }`
    

【讨论】:

  • 感谢 LiveData 的推荐。我会使用,但是我在项目中有数百个现有的过滤和排序的子列表列表,它们依赖于 List。将其更改为 LiveData> 将需要对项目进行大规模升级,以便所有过滤和排序列表也返回 LiveData 和太多额外的编码时间。这就是为什么我要为单个 getAllCards() 方法寻找类似 CompletableFuture 的东西。
  • 没有提供其他可靠的答案,所以我给你的答案+150,干杯。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-02
相关资源
最近更新 更多