9

首先我应该提到我正在使用 ActionBarSherlock 库来实现向后兼容性。

我有一个活动,ListFragment它在首次启动时添加了一个。我有一个自定义Loader,我实现并非常密切地遵循AsnycTaskLoader 示例。ListFragment实现了LoaderCallbacks<Cursor>接口。onCreateLoader()添加片段时( , onLoaderFinished())和替换片段时( ),将调用所有适当的回调方法onLoaderReset()

我的onActivityCreated(Bundle)方法如下所示:

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    mAccountsDbAdapter = new AccountsDbAdapter(getActivity().getApplicationContext());

    setHasOptionsMenu(true);
    mCursorAdapter = new AccountsCursorAdapter(getActivity()
            .getApplicationContext(), R.layout.list_item_account, null,
            new String[] { DatabaseHelper.KEY_NAME },
            new int[] { R.id.account_name }, 0);

    setListAdapter(mCursorAdapter); 
    getLoaderManager().initLoader(0, null, this);
}

稍后,将ListFragment替换为另一个 Fragment B。当用户按下后退按钮时,Fragment B 被删除并再次添加 ListFragment。但是,列表是空的,只android:empty显示元素,并且没有调用任何 LoaderCallback 方法。我可以使用调试器来确定getLoaderManager().initLoader(0, null, this);实际调用的,但没有别的。当我将其更改为 时getLoaderManager().restartLoader(0, null, this);,会调用回调,但我的列表仍然为空(尽管有数据,但视图未刷新)。

当我的 ListFragment 返回到布局时,如何让我的 ListFragment 自行刷新?有没有人遇到过这种情况,你是怎么解决的?

仅供参考,这是我的回调方法

    @Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
    return new AccountsCursorLoader(this.getActivity()
            .getApplicationContext());
}

@Override
public void onLoadFinished(Loader<Cursor> loaderCursor, Cursor cursor) {
    mCursorAdapter.swapCursor(cursor);
    mCursorAdapter.notifyDataSetChanged();
}

@Override
public void onLoaderReset(Loader<Cursor> arg0) {
    mCursorAdapter.swapCursor(null);
}

一些注意事项:

  1. 我不能使用setListShown(true)示例中的方法,因为我知道IllegalStateException它不能与自定义内容视图一起使用。
  2. AccountsCursorAdapter扩展了 aSimpleCursorAdapter并且只修改了bindView()方法。
4

7 回答 7

5

尤里卡!!!我找到了(当然是偶然的)

TL;博士;

AccountsListFragment中,我现在在方法中创建我的数据库适配器 ( AccountsDatabaseAdapter) 并在onCreate()方法中关闭它,onDestroy()它现在可以工作了。以前我onActivityCreated()onDestroyView(). 请注意,我不是指 . ListAdapter,而是指我的数据库接口AccountsDbAdapter

尝试长解释:

好吧,我这样做是因为我认为在该方法getActivity()中无法获取上下文。onCreate()事实证明,你getActivity()甚至可以在onActivityCreated()被调用之前。

但我无法真正解释为什么现在这样有效,因为它Loader有自己的DatabaseAdapter对象来检索数据。如果我猜的话,我会说为两个数据库适配器返回相同的数据库对象(数据库被缓存)。这意味着当我关闭一个时onDestroyView(),另一个也关闭并且游标数据集变得无效,从而导致一个空的列表视图。加载器不会重新加载,因为它认为数据没有改变。

但即使是这个解释也不能完全让我满意,因为我在这里尝试过的一些建议的解决方案,比如每次强制重启加载器都不起作用。(在该loadInBackground()方法中,DatabaseAdapter每次都会创建一个新的)。

无论如何,如果您碰巧对正在发生的事情有更好的了解,请在评论中敲定。

感谢大家对此的帮助!

于 2012-06-14T21:37:35.587 回答
2

您是否尝试过在基础数据集更改后强制加载程序在您的活动中重新启动?

尝试:

getLoaderManager().restartLoader(0, null, this);
于 2012-07-18T22:42:03.540 回答
1

尝试forceload()

getLoaderManager().getLoader( 0 ).forceLoad();
于 2012-06-08T13:25:46.503 回答
1

适配器看到的内容:

您观察到空 ListView 的原因是因为返回的 Cursor 的位置仍然指向最后一个元素。当您swap()将光标指向适配器时,适配器会尝试使用while(Cursor.moveToNext())循环进行迭代。因为该循环总是评估 FALSE,所以您的 ListView 会给您一种空光标的错觉。

打印Cursor.getCount()Cursor.getPosition()in的值onLoadFinished()。如果我是正确的,这两个值应该相等。这种索引冲突造成了上述错觉。

为什么适配器会看到这个:

加载程序将尽可能重用光标。如果你为一组没有变化的数据请求加载器,加载器是聪明的,通过 onLoadFinished 返回游标而不做任何额外的工作,甚至不将游标的位置设置为 -1。

ANS手动调用Cursor.moveToPosition(-1)onLoadFinished()解决此问题。

于 2013-05-25T20:24:52.887 回答
0

就我而言,我发现 ListView 出于某种原因根本没有绘制在屏幕上。如果我转到主屏幕然后切换回活动,一切都会按预期显示。所以我搜索了一种强制重绘屏幕的方法,我发现了以下内容:

强制全屏活动在恢复时重新测量/重绘?

根据对该问题的回答,我将以下代码添加到onActivityCreated()我的 ListFragment 的方法中:

getActivity().getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, 0);

有了这个代码,一切都按预期工作。但这仍然是一种解决方法,所以如果有人用更好的解决方案或解释给出了这个问题的答案,我会奖励他们。

于 2012-06-04T15:48:00.170 回答
0

问题可能来自getLoaderManager()哪个不会将回调发送到正确的位置。

如果您使用的是 ActionBarSherlock 那么这意味着您使用的是 Android 2.x 对吗?您是否考虑过使用 Android 支持包 v4?http://developer.android.com/sdk/compatibility-library.html

然后,您将通过调用使用android.support.v4.app.ListFragment并获取您的LoaderManagergetActivity().getSupportLoaderManager()

于 2012-06-09T11:09:17.880 回答
0

由于您使用的是自定义加载器,您知道在使用本机 CursorLoader 时是否有同样的问题吗?如果没有,那么也许,您可以将您的 Loader 与 Android 源代码进行比较,看看它们是否在做不同的事情?

https://github.com/android/platform_frameworks_base/blob/master/core/java/android/content/CursorLoader.java

于 2012-06-09T11:19:20.570 回答