【问题标题】:Weird AsyncTaskLoader behavior奇怪的 AsyncTaskLoader 行为
【发布时间】:2019-11-28 22:14:09
【问题描述】:

我的应用程序从 Internet 下载 JSON 数据并将其显示为 RecyclerView 列表。这是通过 LoaderManager/Loader 方式实现的。通过单击按钮启动操作。

在 onCreate 中,如果该特定加载器已经存在,我调用 initLoader(),以便为其提供新的回调,绑定到新的 Activity(我这样做是为了确保用户在下载过程中旋转屏幕时不会丢失进度)。现在我已经安排好在屏幕旋转时保留有组织的列表数据。例如,如果我加载数据然后旋转屏幕,调用 initLoader() 将正确推断出数据已经加载并调用 onLoadFinished()(我怀疑加载的数据在内部以某种方式缓存)。

让我感到困惑的是 loadInBackground() 也会以某种方式被调用,绝对没有必要。

阅读文档对我来说并没有很清楚。

如何仅在 onCreate() 时将新的回调传递给我的加载器而不调用不必要的操作?

编辑:这是 AsyncTaskLoader 代码。

@NonNull
@Override
public Loader<String> onCreateLoader(int id, final Bundle args) {
    return new AsyncTaskLoader<String>(this) {
        @Override
        protected void onStartLoading() {
            Log.w("DBG", "onStartLoading");
            if (args == null) return;
            Log.w("DBG", "about to forceLoad");
            forceLoad();
        }

        @Override
        public String loadInBackground() {
            Log.w("DBG", "loadInBackground");

            String baseId = args.getString("baseId");
            String quoteId = args.getString("quoteId");
            String exchange = args.getString("exchange");

            Uri uri = buildUri(baseId, quoteId, exchange);

            String txt = uri.toString();
            Log.i("Uri built: ", txt);

            String response = "";
            try {
                URL url = new URL(uri.toString());
                response = getResponseFromHttpUrl(url);
            } catch (IOException e) {
                e.printStackTrace();
            }

            final int PAUSE_SEC = 5;

            try {
                Thread.sleep(PAUSE_SEC * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            return response;
        }
    };
}

【问题讨论】:

  • 您能否提供您的AsyncTaskLoader() 的代码?听起来你在onStartLoading() 中无条件地调用forceLoad()
  • 不完全是,我加了代码

标签: android asynctaskloader


【解决方案1】:

根据Making loading data lifecycle aware blog post

我们现在可以将结果保存在成员变量中,并在配置更改后立即返回它们,方法是立即在我们的 onStartLoading() 方法中调用 deliverResult()。请注意,如果我们有缓存数据,我们是如何不调用 forceLoad() 的——这是我们避免不断重新加载数据的方法!

检查您的 args 是否为 null 是不够的,因为您对 initLoader() 的第二次调用通常会将相同的 args 传递给您的加载程序。相反,由您的 AsyncTaskLoader 缓存结果并使用已加载数据的存在来明确不从 onStartLoading() 调用 forceLoad()

请注意,根据同一篇博文:

如果您正在寻找一种不依赖于 Loaders 的现代、灵活的解决方案(此处选择的解决方案),请查看 Lifecycle Aware Data Loading with Architecture Components 博客文章。

您可能会找到一个基于 ViewModel(也可以在配置更改中保留)和 LiveData(用于观察 Activity/Fragment 中的结果)的解决方案,这样可以编写更少的代码并且更容易理解。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-08
    • 2015-07-20
    • 2010-10-03
    • 2021-07-12
    • 2013-10-04
    • 2019-01-23
    相关资源
    最近更新 更多