无法在onLoadFinished中执行此操作

Tob*_*ias 19 android android-fragments

我正在创建一个带有一个活动和许多片段的新示例Android应用程序.

起初我正在启动"OverviewFragment"(我的仪表板),它应该显示一些基本信息.我的OverviewFragment使用"AccountProvider"(ContentProvider)加载信息.如果数据库为空,则应将OverviewFragment替换为我的WelcomeFragment ...

这是一些代码:

public class OverviewFragment extends BaseFragment
    implements LoaderManager.LoaderCallbacks {

private static final int LOADER_ACCOUNTS = 10;
private static final int LOADER_TRANSACTIONS = 20;

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

    getLoaderManager().initLoader(LOADER_ACCOUNTS, null, this);
    //getLoaderManager().initLoader(LOADER_TRANSACTIONS, null, this);
}

@Override
public Loader onCreateLoader(int id, Bundle args) {
    Uri uri = null;
    String[] projection = null;
    String selection = null;
    String[] selectionArgs = null;
    String sortOrder = null;

    switch (id) {
        case LOADER_ACCOUNTS:
            uri = WalletProvider.CONTENT_URI;
            projection = new String[]{DBHelper.ACC_ID, DBHelper.ACC_TITLE};
            sortOrder = DBHelper.ACC_TITLE;
            break;
    }
    CursorLoader cl =  new CursorLoader(getActivity(),
            uri, projection, selection, selectionArgs, sortOrder);
    return cl;
}

@Override
public void onLoadFinished(Loader loader, Object data) {
    switch (loader.getId()) {
        case LOADER_ACCOUNTS:
            bindAccounts((Cursor) data);
            break;
    }

}

@Override
public void onLoaderReset(Loader loader) {

}

private void bindAccounts(Cursor cursor) {
    boolean showCreateWallet = true;


    if (cursor != null && cursor.moveToFirst()) {
        showCreateWallet = false;
    }

    if (showCreateWallet) {
        listener.changeFragment(new WalletCreateFragment());
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的主要活动

    @Override
public void changeFragment(Fragment fragmentToLoad) {
    FragmentManager fragmentManager = getSupportFragmentManager();
    fragmentManager.beginTransaction()
            .replace(R.id.container, fragmentToLoad)
            .commit();
}
Run Code Online (Sandbox Code Playgroud)

现在......如果我用空数据库启动我的应用程序,我会收到你在标题中看到的错误..

我知道我不应该更改onLoadFinished函数中的片段....但我在哪里可以做到?:P

抱歉我的英文=)

pab*_*dez 30

这是android的一个bug.要解决这个问题,请使用Handler来替换/添加/调用onLoadFinished中的Fragment,如下所示:

final int WHAT = 1;
Handler handler = new Handler(){
    @Override
    public void handleMessage(Message msg) {                    
        if(msg.what == WHAT) changeFragment(fragmentToLoad);            
    }
};
handler.sendEmptyMessage(WHAT);
Run Code Online (Sandbox Code Playgroud)

  • `handler.post(Runnable)`也可以工作,看起来更简洁. (14认同)
  • 如果这是一个错误,您可以链接到该问题,或进一步讨论该错误? (13认同)
  • 它不是一个错误,它是预期的行为,你必须明确承认这可能导致国家损失.请参阅https://groups.google.com/forum/#!topic/android-developers/dXZZjhRjkMk/discussion (4认同)

bee*_*tra 9

这不是一个错误,但它不是一个简单的问题.onLoadFinished可以在任何时间运行,包括在保存活动状态之后.然后,框架将不会自动保存生成的片段更改.您必须明确允许这样使用commitAllowingStateLoss

在以下文件中onLoadFinished:

在先前创建的加载程序完成其加载时调用.请注意,通常,在此调用中,不允许应用程序提交片段事务,因为它可能在保存活动状态后发生.有关此问题的进一步讨论,请参阅FragmentManager.openTransaction().

引用Dianne Hackborn从其他答案的评论中提到的帖子:

只需了解如果活动的片段状态已经保存,如果稍后从状态重新启动,则代码将需要正确更新它.

[...]

作为加载器的结果,显示对话框(或在UI中执行任何其他重大转变)是一种糟糕的用户体验.这就是你正在做的事情:将一些操作设置为在后台运行一段不确定的时间,一旦完成,可能会在用户面前抛出一些东西,将它们从他们正在做的事情中拉出来.

我的建议是以与显示数据相同的方式向用户显示有关加载器结果的任何信息.

如果您(和您的用户)对用户体验没有问题,您可以使用commitAllowingStateLoss更新片段.