AsyncTaskLoader.deliverResult()实际上是做什么的?

9

我正在尝试理解AsyncTaskLoaders的一些细节。这可能对其他人来说很明显,但我找不到一个清晰的示例或定义来演示和解释当您覆盖deliverResult()方法时会发生什么。实际上传递了什么?这如何与调用对象交互?我可以看到使用super.deliverResult,它从类中传递一个私有对象。那么,加载器自动知道要与“传递的结果”关联什么吗?我完全困惑了。


你有关于这个查询的答案吗?我也很困惑。 - Sumit Trehan
4个回答

27

看起来我有点晚了,但无论如何...

这个中介步骤在后台加载和UI线程的回调onLoadFinished()被调用之间的一个主要优点之一是

  1. loadInBackground()
  2. deliverResult()
  3. 回调onLoadFinished()

它为我们提供了一种从AsyncTaskLoader类内部快捷跳过整个加载过程的方法。 如果有缓存数据,这可以很好地用于在您的AsyncTaskLoader中缓存加载结果并阻止后台加载

为什么我们要这样做呢?难道不是加载器处理那些可怕的活动生命周期问题(例如旋转设备)、维护状态(如缓存数据)并有一种在底层数据更改时获得更新的方法(CursorLoader)的全部内容吗?
好吧,是的,但这并不是全部故事。

Consider this use case: 你的应用程序(带有AsynTaskLoader)已经运行并将数据加载到了用户界面中。然后,你转到Twitter应用程序查看一些新闻并返回到你的应用程序。如果没有缓存,当返回到你的应用程序时,加载程序将重新加载。这种行为与配置更改后不同,例如旋转设备,在这种情况下不会发生重新加载。
那么,我们如何防止加载程序在我们将应用程序发送到后台并稍后再次返回时重新获取数据?
解决方案: 1. 在你的AsyncTaskLoader实现中创建一个缓存成员变量。 2. 重写deliverResult()方法,使得在调用超类的deliverResult()之前,首先将获取的数据保存在缓存中。 3. 在onStartLoading()方法中检查是否有缓存数据,如果有,则让你的AsyncTaskLoader直接传递缓存数据。否则,开始加载。

这里有一个链接,指向一个实现了此行为的样例应用程序(sample app which implements this behaviour)。 这只是一款“玩具应用程序”,因此是Udacity当前版本“Developing Android Apps”基础课程的一部分。而这个链接则指向该课程中处理此问题的相应视频。(该课程是免费的,但您仍需要在Udacity上注册)。

简而言之,这个应用程序展示了一个UI,用户可以在其中输入搜索查询以搜索GitHub的repos(通过GitHub API),将结果搜索URL显示在TextView中,并在另一个TextView中显示从GitHub获取的原始JSON。
整个操作都发生在MainActivity.java中,这里的相关部分位于实现为匿名内部类的AsyncTaskLoader中:
  • For step 1, just introduce a member variable in your AsyncTaskLoader implementation that's meant to serve as your data cache.

    /* This String will contain the raw JSON
       from the results of our Github search */
    String mGithubJson;
    
  • For step 2, override deliverResult() as to cache the loading result.
    When loadInBackground() has finished, it passes its return value to deliverResult(). It does so anyway, but now that we've overridden deliverResult() we can step right in and store our fetched data into the cache member variable which we've created with just so good foresight. And finally, we chain up to the super class implementation of deliverResult() with super.deliverResult() which will pass-on the result to the callback method onLoadFinished(), running on the UI thread.

    @Override
    public void deliverResult(String githubJson) {
        mGithubJson = githubJson;
        super.deliverResult(githubJson);
    }
    
  • For step 3, check in onStartLoading() whether or not we've got cached data.
    If we don't have cached data (yet), just force the loading to begin with a call to forceLoad(). But if we do have cached data, just call deliverResult(yourCachedDataGoesHere) and pass-in the cached data as argument.

    if (mGithubJson != null) {
        deliverResult(mGithubJson);
    } else {
        forceLoad();
    }
    

    So, if you now switch back and forth between your app and some other app(s), you'll notice that no reloading takes place, as the loader will just use your cached data.


感谢这个更新。我已经修改了答案。+1 - angryITguy
我已经尝试通过解决方案项目进行调试,但它仍然从互联网获取数据!这个语句(https://github.com/udacity/ud851-Exercises/blob/student/Lesson05b-Smarter-GitHub-Repo-Search/T05b.03-Solution-PolishAsyncTask/app/src/main/java/com/example/android/asynctaskloader/MainActivity.java#L191)从未为真! - Muhammad Gelbana
@MuhammadGelbana 所以,我也一直在调试那个“GitHub查询”项目,它确实按预期工作。 第一次获取数据后,您是否离开了应用程序(例如通过HOME按钮而不是通过BACK按钮退出应用程序!)并返回到应用程序?否则,您将重新开始,缓存的数据将丢失,因此加载器将再次获取数据。 - croworc
我一直在调试同一个应用程序,但是我不明白为什么在调用deliverResult()之后onLoadFinished()没有被调用。你有什么想法吗? - imran.razak
可能是我在StackOverFlow上读过的最好的答案之一。 - getsadzeg

5
假设数据正在后台加载,此时用户按下HOME按钮退出应用程序,当用户回到应用程序时,加载已完成。因此,我们已经拥有了数据,然后AsyncTaskLoader将调用deliverResult()方法,将数据传递给onLoadFinished()方法进行显示。
当用户回到应用程序时,在调用loadInBackground()之前会调用onStartLoading()。在此方法中,我们可以检查数据是否为空,如果不为空,则调用deliverResult()并将结果发送到onLoaderFinished(),这样可以防止重新加载数据。
当我们按HOME键退出应用程序并返回时,它不会创建新的Loader,而是尝试加载旧的数据。 每个方法的顺序

谢谢。你能为此提供任何来源吗? - angryITguy
1
你可以在此链接中找到更多关于编程的相关信息:https://classroom.udacity.com/courses/ud851/lessons/ed13cc93-2861-43bf-b7ed-395a166ab975/concepts/0e29911f-bacc-4358-a1c6-b7d55e327f4a - Yanbin Hu
@YanbinHu 不错的图表! :-) 请问您使用了哪个应用程序? 顺便说一下,方法名称doInBackground应该改为loadInBackground。 另外,Android文档提供了一个有用的示例,介绍了AsyncTaskLoader以及如何使用deliverResult()、forceLoad()、onStartLoading()等: https://developer.android.com/reference/android/content/AsyncTaskLoader.html - croworc

0

我能找到的唯一有意义的答案是基于this链接中的描述。

“注册侦听器以在加载完成时接收Loader的结果。对于每个Loader,LoaderManager都会注册一个OnLoadCompleteListener,它将通过调用onLoadFinished(Loader loader,D result)将Loader的交付结果转发给客户端。Loader应使用Loader#deliverResult(D result)调用将结果传递给这些已注册的侦听器。”

当您有AsyncTask的侦听器并希望将结果发送回它们时,似乎可以使用deliverResult。我会说这很不常见。 {{link2:Android文档}}甚至更少描述:

“将加载的结果发送到已注册的侦听器。只应由子类调用。必须从进程的主线程调用。

参数

data:加载的结果”


-1

deliverResult 在 doInbackground 完成后起作用。它将结果 D(由 doInBackground 返回)发送到调用线程。您可能希望重写它以清理数据,但是您可以在 doInBackground 中进行清理而无需重写 deliverResult。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接