Android:LoaderCallbacks.OnLoadFinished两次调用

Luk*_*szS 53 android loader

我注意到使用Android Loaders和Fragments的奇怪情况.当我调整方向更改onLoadFinished后调用LoaderManager.initLoader()时(尽管文档建议我应该为此做好准备),但在此之后调用它两次.以下链接指向相同情况的Google群组中的帖子https://groups.google.com/forum/?fromgroups#!topic/android-developers/aA2vHYxSskU.我编写了示例应用程序,其中我只在Fragment.onActivityCreated()中初始化简单的Loader来检查是否会发生这种情况.有人注意到了吗?

Bog*_*rac 38

你可以将initLoader()方法放在Fragment的onResume()回调中; 那么Loader的onLoadFinished()将不再被调用两次.

    @Override
public void onResume()
{
    super.onResume();
    getLoaderManager().initLoader(0, null, this);
}
Run Code Online (Sandbox Code Playgroud)

  • 我不知道......我在加载器框架中发现了很多愚蠢的错误,我甚至无法开始描述......好吧,也许不是错误,但有些实现并不容易集成. (6认同)
  • 这看起来不是一个好的解决方案。假设您从 onResume initLoader 中的片段启动另一个活动...恢复此片段将再次调用 initloader。 (2认同)

Mat*_*att 28

这个问题表明我自己使用CursorLoader返回一个已经关闭的Cursor:

android.database.StaleDataException: Attempted to access a cursor after it has been closed.
Run Code Online (Sandbox Code Playgroud)

我猜这是一个错误或疏忽.虽然将initLoader()移动到onResume可能会起作用,但我能够做的就是在完成后删除Loader:

要启动加载器(在我的onCreate中):

  getLoaderManager().initLoader(MUSIC_LOADER_ID, null, this);
Run Code Online (Sandbox Code Playgroud)

在我完成它之后(基本上在onLoadFinished结束时)

  getLoaderManager().destroyLoader(MUSIC_LOADER_ID);
Run Code Online (Sandbox Code Playgroud)

这似乎表现得如预期,没有额外的电话.

  • `destroyLoader()`是最可靠的修复,特别是在处理必须在`onCreate`或`onResume`生命周期之外启动的Loader时. (3认同)

小智 6

initLoader文档说,

如果在调用点调用者处于启动状态,并且请求的加载器已经存在并且已经生成了它的数据,则回调onLoadFinished(Loader,D)

我建议你在这个示例中实现类似onStartLoading函数的东西

要快速测试,您可以尝试:

@Override protected void onStartLoading() {
    forceLoad();
}
Run Code Online (Sandbox Code Playgroud)

这个启动loadInBackground函数然后在Fragment中onLoadFinished.

无论如何,如果你附上一些代码,我会尽力给你更多的帮助.


小智 5

我这样解决了两次调用onLoadFinished的问题。在您的Fragment.onActivityCreated()中,像这样初始化您的加载器

if (getLoaderManager().getLoader(LOADER_ID) == null) {
    getLoaderManager().initLoader(LOADER_ID, bundle, loaderCallbacks);
} else {
    getLoaderManager().restartLoader(LOADER_ID, bundle, loaderCallbacks);

}
Run Code Online (Sandbox Code Playgroud)

在这里,loaderCallbacks实现了通常的Loader回调

private LoaderManager.LoaderCallbacks<T> loaderCallbacks
        = new LoaderManager.LoaderCallbacks<T>() {
    @Override
    public Loader<T> onCreateLoader(int id, Bundle args) {
        ...
        ...
    }

    @Override
    public void onLoadFinished(Loader<T> loader, T data) {
        ...
        ...
    }

    @Override
    public void onLoaderReset(Loader<T> loader) {
        ...
        ...
    }
};
Run Code Online (Sandbox Code Playgroud)