Android - onLoadFinished未被调用

10

我遇到了Loader的问题。

我有一个Activity,从本地数据库检索记录并显示列表。当Activity启动时,通过LoaderManager.initLoader()方法自动加载记录。

还有可能通过ActionBarSherlock中的刷新按钮手动刷新列表。但是,在完成添加记录到数据库的另一个活动后,onLoadFinished不会被调用。

我正在使用SimpleCursorLoader,以下是活动中的代码片段:

@Override
public void onStart() {
   ...
   getSupportLoaderManager().initLoader(0, null, this);
}

@Override
public void onPause() {
   ...
   getSupportLoaderManager().destroyLoader(0);
}

public void refreshRecords() {
   getSupportLoaderManager().restartLoader(0, null, this);
}

@Override
public Loader<Cursor> onCreateLoader(int id, final Bundle args) {
Loader<Cursor> l = new SimpleCursorLoader(this) {
    @Override
    public Cursor loadInBackground() {
        return recordDAO.getCursor();
    }
};
l.forceLoad();
return l;
}

@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor c) {
   // updateUI
}

@Override
public void onLoaderReset(Loader<Cursor> loader) {
}
问题在于完成另一个活动后,将调用onLoaderCreate,但不会调用onLoaderFinished
经过一些调试,我发现SimpleCursorAdapter.deliverResults()也被调用了,但最终停留在.. if (isReset()) { ..
我错过了什么吗?如何强制重新加载数据?
提前感谢。

你可以在这里找到解决方案: https://dev59.com/go3da4cB1Zd3GeqPtwLO 或者在这里: https://dev59.com/FWw05IYBdhLWcg3wkik- - B-GangsteR
5个回答

16

多亏了这个讨论,我终于找到了解决这个问题的方法:

https://groups.google.com/forum/#!topic/android-developers/DbKL6PVyhLI

public static <T> void initLoader(final int loaderId, final Bundle args, final LoaderCallbacks<T> callbacks,
        final LoaderManager loaderManager) {
    final Loader<T> loader = loaderManager.getLoader(loaderId);
    if (loader != null && loader.isReset()) {
        loaderManager.restartLoader(loaderId, args, callbacks);
    } else {
        loaderManager.initLoader(loaderId, args, callbacks);
    }
}

另外,自Support库28起,请确保不要在Fragment.onCreate()内调用initLoader。根据更新后的文档所述,

通常在activity的onCreate()方法或fragment的onActivityCreated()方法中初始化Loader。

请参见https://developer.android.com/guide/components/loaders


4
几乎正确的解决方案:如https://groups.google.com/forum/#!topic/android-developers/DbKL6PVyhLI所述(我进行了实验),重置条件是!loader.isReset(),即“仅当装载机未重置时才应重新启动加载程序。” (由Etienne编写)。 请更新您的答案。 - Pascal

4

RaB的解决方案对我没有用

我的有效解决方案是在重新启动之前总是销毁加载器。

Loader<Cursor> loader = mLoaderManager.getLoader(mKeyLoader);
if (loader != null)
{
    mLoaderManager.destroyLoader(mKeyLoader);
}
mLoaderManager.restartLoader(mKeyLoader, args, this);

谢谢。我终于找到了一种方法来强制加载程序始终调用onLoadFinished方法。 - MistaGreen

2
除了RaB的回答之外,如果您正在使用自定义Loader,请确保在覆盖deliverResult()时调用super:
@Override
public void deliverResult(D data) {
    super.deliverResult(data); // <--onLoadFinished() will not be called if you don't call this
    ...
}

1

就我个人而言,我曾经尝试在第一次onLoadFinished被调用之前立即重新启动加载程序,导致两者都没有被调用,我遇到了类似的问题。

以下方法对我有效:

if( loader == null )
    loader = loaderMngr.initLoader(
        0, null, myLoaderCallbacks
        ); 
else if( loader.isAbandoned() )
    return;
else
    loaderMngr.restartLoader(
        0, null, myLoaderCallbacks
        );    

1

检查支持库。使用import android.support.v4.app导入,不要使用android.app.loadermanager。

import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;

初始化部分

    LoaderManager mLoaderManager=getSupportLoaderManager(); 

      LoaderManager.LoaderCallbacks<Cursor> mCursorLoaderCallbacks=new LoaderManager.LoaderCallbacks<Cursor>() {
                @Override
                public Loader<Cursor> onCreateLoader(int id, Bundle cursor) {
                      return new CursorLoader(getActivity(), MediaStore.Video.Media.EXTERNAL_CONTENT_URI, COLUMNS_OF_INTEREST, null, null,
                            MediaStore.Video.Media.DATE_ADDED + " DESC");
                }
                @Override
                public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
                }


                @Override
                public void onLoaderReset(Loader<Cursor> loader) {              
               }
            };

  mLoaderManager.initLoader(URL_LOADER_EXTERNAL, null, mCursorLoaderCallbacks);

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