如何从存储库访问和返回 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 的结果?的主要内容,如果未能解决你的问题,请参考以下文章

从 AsyncTask Android 返回数据

查询访问存储库而不返回数据

无法从 AsyncTask 返回值;使用接口和委托;

如何从服务器下载图像如果使用Asynctask存储在ArrayList中的URL?

AsyncTask 不返回值

在返回结果之前等待 AsyncTask.execute(()) 完成