如何从存储库访问和返回 AsyncTask 的结果?
Posted
技术标签:
【中文标题】如何从存储库访问和返回 AsyncTask 的结果?【英文标题】:How to access and return the result of an AsyncTask from a repository? 【发布时间】:2021-01-10 21:39:57 【问题描述】:我是编码新手,已经投入了很多时间,感觉自己正在一步一步地进步。但是,我遇到了一个问题,即使经过几天的研究和尝试不同的事情,我也无法解决。抱歉,您的解释过于冗长或糟糕 - 我试图尽可能地解释清楚。
提前非常感谢您!
我将描述问题以及我首先尝试了什么。然后,在下方,您可以看到有关我的最终目标的更多信息,以及我为什么考虑按原样构建代码。最后你可以找到我到目前为止的代码。
问题和潜在解决方案
我尝试编写的应用程序使用 MVVM 结构 - 我使用 android Room 并有一个(预填充的)数据库、两个实体和相应的 DAO、一个视图模型和一个存储库。
在我的存储库中,我试图包含一个新方法“getEntriesCountById”,它接受一个整数(“correspondingChallengeId”)并将其传递给一个新的 AsyncTask。给定该 id,AsyncTasks 在 EntryDao 中运行相应的查询以检索另一个用作“entriesCount”的整数。
但是,我找不到在我的存储库方法“getEntriesCountById”中返回该 asyncTask 的结果(“entriesCount”)的方法。我假设我需要返回它,以便我可以从另一个活动或 viewModel 调用该方法。
我尝试将返回变量包装在 LiveData 中,并尝试使用 PostExecute 方法,但找不到使其工作的方法。我还研究了弱引用和“delegate”函数的用法,但不知何故我无法返回那个“entriesCount”。顺便说一句 - 我成功地获取并显示了所有条目的列表(在回收站视图中)。我觉得这真的只是我错过的一小步。 (顺便说一下,下面代码中的存储库包括操作“返回所有可用条目的列表和相应的 asyncTask - 我想这与这个问题无关。)
背景信息
更准确地说,所描述的实体称为“ProgressEntry”,它基本上用作记录某人在不同挑战(跑步、游泳、弹吉他等)中的进度的表格。它包括一个(主要的、唯一的)entryId、一个对应的ChallengeId、一个entryDate 和一个entryValue。表中的一条记录可以是:例如:1, 3, 09/10/2020, 5000) 表示该记录具有唯一 id “1”,对应的ChallengeId “3”(标识相应的挑战,例如正在运行),特定日期和值,例如5000米。显然,同一个对应的ChallengeId 可以有多个条目(例如,如果一个人在9 月份跑步5 次)。
在存储库中,我想使用异步任务来处理各种 DAO SQL 查询,例如“返回对应ChallengeId = 1 的进度条目列表,或“返回具有最高值的条目”或“返回一个条目的数量特别的挑战”(如我上面所说的)。
代码 sn-ps
我的 ProgressEntry 类
@Entity(tableName = "progress_entries_table")
public class ProgressEntry
@PrimaryKey (autoGenerate = true)
private int progressEntryPrimaryId;
//gives information about correspondingChallenge
private int correspondingChallengeId;
//date for which entry was recorded
private String progressEntryDate;
//progress value for particular entry
private int progressEntryValue;
public ProgressEntry(int correspondingChallengeId, String progressEntryDate, int progressEntryValue)
this.correspondingChallengeId = correspondingChallengeId;
this.progressEntryDate = progressEntryDate;
this.progressEntryValue = progressEntryValue;
(包括所有字段/列的 setter 和 getter)
我的 ProgressEntry Dao(查询)
//return number of entries for given id (representing unique challenge)
@Query("SELECT count(*) FROM progress_entries_table WHERE correspondingChallengeId =:id")
Integer getEntriesCountById(int id);
我的仓库
注意:我描述的 AsyncTask 位于顶部/中间。底部的方法“getAllAvailableProgressEntries”是无关紧要的,实际上在我的应用程序中工作得很好。我包含它是因为它可能会提示我做错了什么。
public class Repository
private ProgressEntryDao progressEntryDao;
private LiveData<List<ProgressEntry>> allAvailableProgressEntries;
public Repository(Application application)
Database database = Database.getInstance(application);
progressEntryDao = database.progressEntryDao();
allAvailableProgressEntries = progressEntryDao.getAllAvailableProgressEntries();
//--------------------------------------------------------
public Integer getEntriesCountById(Integer correspondingChallengeId)
new CountAsyncTask(progressEntryDao).execute(correspondingChallengeId);
//return... - How do I return the Integer (entriesCount)
//passing and Integer (correspondingChallengeId) and result is also supposed to be an Integer (entriesCount)
private static class CountAsyncTask extends AsyncTask<Integer, Void, Integer>
private ProgressEntryDao progressEntryDao;
//Constructor for AsyncTask
public CountAsyncTask(ProgressEntryDao progressEntryDao)
this.progressEntryDao = progressEntryDao;
//doInBackground method accessing my Dao and the required method
@Override
protected Integer doInBackground(Integer... integers)
return progressEntryDao.getEntriesCountById(integers[0]);
//onPostExecute method - It should handle the result, right?
@Override
protected void onPostExecute(Integer integer)
super.onPostExecute(integer);
//--------------------------------------------------------
public LiveData<List<ProgressEntry>> getAllAvailableProgressEntries()
return allAvailableProgressEntries;
public void insertProgressEntry(ProgressEntry progressEntry)
new InsertProgressEntryAsyncTask(progressEntryDao).execute(progressEntry);
private static class InsertProgressEntryAsyncTask extends AsyncTask<ProgressEntry, Void, Void>
private ProgressEntryDao progressEntryDao;
//Constructor
private InsertProgressEntryAsyncTask(ProgressEntryDao progressEntryDao)
this.progressEntryDao = progressEntryDao;
@Override
protected Void doInBackground(ProgressEntry... progressEntries)
progressEntryDao.insert(progressEntries[0]);
return null;
我如何从其他活动调用方法 (为了简单起见,不使用视图模型。)
public class ExperimentActivity extends AppCompatActivity
private TextView textView;
private Repository repository;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_experiment);
repository = new Repository(getApplication());
textView = findViewById(R.id.txtView);
textView.setText(String.valueOf(repository.getEntriesCountById(2)));
【问题讨论】:
【参考方案1】:AsyncTask 已被弃用,因此您不应再使用它(请参阅AsyncTask docs)。 还提到了您应该使用什么:coroutines。 它们与 LiveData 配合得很好,因此您最终可能会得到一个最新的解决方案。 由于这可能非常令人困惑,我建议您查看 codelab,它说明了如何将 Room + Coroutines + LiveData 放在一起。
【讨论】:
感谢您的回答,对于迟到的跟进深表歉意!我研究了协程 - 但是,还有没有办法用 Java(而不是 Kotlin)来做呢?我现在还尝试过的是使用某种接口来获取执行后的值,但我仍然无法从数据库中获取该值(顺便说一句。不能支持您的评论,因为我显然没有足够的声誉:D) 如果你想在 Java 中实现,请查看 RxJava 广告,了解更新的线程解决方案以上是关于如何从存储库访问和返回 AsyncTask 的结果?的主要内容,如果未能解决你的问题,请参考以下文章