我试图了解AsyncTaskLoaders的一些更好的点。这对其他人来说可能很明显,但我找不到一个明确的示例或定义来演示和解释当您覆盖该deliverResult()
方法时会发生什么。实际交付的是什么?这如何与调用对象交互?我可以看到 of 的使用super.deliverResult
,它从类中传递了一个私有对象。那么,加载程序是否会自动知道与“交付结果”相关联的内容。我完全糊涂了。
4 回答
看来我参加聚会有点晚了,但无论如何...
onLoadFinished()
在后台加载和 UI 线程的回调被调用 之间的中间步骤的主要优点之一
loadInBackground()
deliverResult()
和- 回调
onLoadFinished()
是它为我们提供了一种从类中缩短整个加载过程AsyncTaskLoader
的方法。这可以很好地用于在 AsyncTaskLoader 中缓存加载结果,并在存在缓存数据时防止后台加载发生。
我们为什么要这样做?加载器的全部意义不在于处理那些可怕的活动生命周期问题(例如旋转设备)、维护状态(例如缓存数据)以及在底层数据更改时获得更新的方法(CursorLoader)吗?
嗯,是的,但这不是故事的全部。
考虑这个用例:
您的应用程序(带有 AsynTaskLoader 的应用程序)已启动并运行,并且已经将数据加载到您的 UI 中。然后,您切换到您的 Twitter 应用程序以查看一些新闻并返回您的应用程序。
如果没有缓存,则在返回您的应用程序时,加载程序会重新加载。此行为不同于配置更改后的行为,例如旋转您的设备,在这种情况下不会发生重新加载。
那么,如果我们只是将我们的应用程序发送到后台并稍后再次返回,我们将如何防止加载程序重新获取数据?
解决方案
- 在您的实现中创建一个缓存成员变量。
AsyncTaskLoader
- 覆盖
deliverResult()
,以便在调用超类的deliverResult() 实现之前,首先将获取的数据保存在缓存中。 onStartLoading()
检查是否有缓存的数据,如果有,让您的 AsyncTaskLoader 交付它。否则,开始加载。
这是实现此行为的示例应用程序的链接。它只是一个“玩具应用”,也是 Udacity 当前版本的“开发 Android 应用”基础课程的一部分。这是该课程中处理此问题的相应视频的链接。(该课程是免费的,但您仍然需要注册 Udacity)。
简而言之,这个应用程序演示的是一个 UI,用户可以在其中输入搜索查询以搜索 GitHub 的存储库(通过 GitHub API),在 TextView 中显示结果搜索 URL,以及在另一个 TextView 中显示从 GitHub 获取的原始 JSON .
整个动作发生在 just 中MainActivity.java
,这里的相关部分在AsyncTaskLoader
作为匿名内部类实现的内部类中:
对于第 1 步,只需在您的 实现中引入一个用作数据缓存的成员变量。
AsyncTaskLoader
/* This String will contain the raw JSON from the results of our Github search */ String mGithubJson;
对于第 2 步,覆盖
deliverResult()
as 以缓存加载结果。
完成loadInBackground()
后,它将返回值传递给deliverResult()
. 无论如何它都会这样做,但是现在我们已经覆盖了 DeliverResult(),我们可以直接介入并将我们获取的数据存储到我们以非常好的远见创建的缓存成员变量中。最后,我们链接到 DeliverResult() 的超类实现,super.deliverResult()
它会将结果传递给onLoadFinished()
在 UI 线程上运行的回调方法。@Override public void deliverResult(String githubJson) { mGithubJson = githubJson; super.deliverResult(githubJson); }
对于第 3 步,检查我们是否有缓存
onStartLoading()
数据。 如果我们(还)没有缓存数据,只需强制加载以调用. 但如果我们确实有缓存数据,只需调用并传入缓存数据作为参数。forceLoad()
deliverResult(yourCachedDataGoesHere)
if (mGithubJson != null) { deliverResult(mGithubJson); } else { forceLoad(); }
因此,如果您现在在您的应用程序和其他一些应用程序之间来回切换,您会注意到不会发生重新加载,因为加载程序只会使用您的缓存数据。
假设在后台加载数据时,此时用户按下HOME键并存在应用程序,当用户返回应用程序时,加载已完成。所以我们已经有了数据,然后AsyncTaskLoader
会调用deliverResult()
方法,将数据传递给onLoadFinished()
方法进行显示。
当用户返回应用程序时,onStartLoading()
正在调用之前loadInBackground()
。在这个方法中,我们可以检查我们的数据是否为空,如果不为空,我们调用deliverResult()
并将结果发送到onLoaderFinished()
,这样可以防止重新加载数据。
当我们按 HOME 存在应用程序然后返回时,它不会创建新的 Loader,而是旧的 loader 会尝试加载数据。
我能找到的唯一有意义的答案是基于此链接中的描述。
“一个注册的侦听器,用于在完成加载时接收加载器的结果。对于每个加载器,LoaderManager 注册一个 OnLoadCompleteListener,它将通过调用 onLoadFinished(Loader loader, D result) 将加载器交付的结果转发给客户端。加载器应该通过调用 Loader#deliverResult(D result) 将结果传递给这些注册的侦听器。”
当您有 AsyncTask 的侦听器并希望将结果发送回给它们时,似乎使用了 deliverResult。我会说这并不常见。Android 文档的描述性更差:
“将加载结果发送给注册的监听器。只能由子类调用。必须从进程的主线程调用。
参数
数据:加载的结果”
DeliverResult 在 doInbackground 完成后工作。它将结果 D(由 doInBackground 返回)发送到调用线程。您可能希望覆盖它以清理数据,但您可以在 doInBackground 中进行清理而不覆盖 DeliverResult。