2011-10-12 23 views
16

我试图使用FragmentActivityViewPager来显示动态列表Fragments。有很多关于如何做静态版本的例子。我的问题是我显示的列表需要动态加载,也可以根据用户输入(添加/删除)进行更改。我正尝试使用自定义的android.support.v4.content.Loader加载可用于构建我的列表的数据集。Android - 使用FragmentActivity + Loader更新FragmentStatePagerAdapter的问题

一切顺利在我的设置很好,直到我去点时,我想更新适配器,并发出此时该代码被执行(从FragmentStatePagerAdapterFragmentStatePagerAdapter#notifyDataSetChanged()呼叫

public void finishUpdate(View container) 
{ 
    if(mCurTransaction != null) 
    { 
     mCurTransaction.commit(); // BANG!!! The exception is thrown 
     mCurTransaction = null; 
     mFragmentManager.executePendingTransactions(); 
    } 
} 

提交失败与交易此消息:

java.lang.IllegalStateException: Can not perform this action inside of onLoadFinished

因为内FragmentManagerImpl执行该代码:

private void checkStateLoss() { 
    if (mStateSaved) { 
     throw new IllegalStateException(
       "Can not perform this action after onSaveInstanceState"); 
    } 
    if (mNoTransactionsBecause != null) { 
     throw new IllegalStateException(
       "Can not perform this action inside of " + mNoTransactionsBecause); 
    } 
} 

事实证明,mNoTransactionsBecause值不为空,它是在LoaderManagerImpl.LoaderInfo设定时,返回的结果回onLoadFinished

我一直在寻找各种变量试图以某种方式改变tramsaction.commit()transaction.commitAllowingStateLoss()但一切相关交易似乎是私人的,或者至少是包裹保护的。

如果我可以做我需要做的事情(以及如何做),有人可以给我一个总体想法吗?

只是要注意的是我的代码工作正常,如果不是使用装载机我的AsyncTask

+0

你已经能够找出正确的方法用装载机做到这一点?我面临同样的问题。我可以使用'transaction.commitAllowingStateLoss()'来实现它的功能,但是知道Google希望我们做什么仍然很好......似乎应该有一种在加载数据后执行片段事务的方法使用加载程序... – ashughes

+0

我通常放弃了这一点,并使用ModernTaskLoader以限制汇集 – Bostone

+0

什么是ModernTaskLoader?在任何地方都找不到任何信息... – ashughes

回答

35

我有一个非常类似的问题,并通过在碎片上使用处理程序来解决它。

我想表现的onLoadFinished(),类似于以下

public class MyFragment extends Fragment 
    implements LoaderManager.LoaderCallbacks<T> { 

    public void onLoadFinished(Loader<T> loader, T data) { 
     showDialog(); 
    } 

    public void showDialog() { 
     MyAlertDialogFragment fragment = new MyAlertDialogFragment(); 
     fragment.show(getActivity().getSupportFragmentManager(), "dialog"); 

    } 
} 

一个警告对话框但是,这给了一个错误

不能的onLoadFinished

内执行此操作解决方案是在该片段中添加处理程序,以便显示对话框

private Handler handler = new Handler() { 
    @Override 
    public void handleMessage(Message msg) { 
     if(msg.what == MSG_SHOW_DIALOG) { 
      showDialog(); 
     } 
    } 
}; 

然后修改onLoadFinished(...)将消息发送到处理程序,而不是

public void onLoadFinished(Loader<T> loader, T data) { 
     handler.sendEmptyMessage(MSG_SHOW_DIALOG); 
    } 
+11

或者您可以将处理程序发布到runnable。 'Handler h = new Handler(Looper.getMainLooper());h.post(new Runnable(){....});'等 –

+1

@ Chris.Jenkins Ian的实现更高效,因为它只需要一个对象分配。 :) –

+0

@AlexLockwood除非在高性能场景中一次创建1000个对象,否则不是真正的问题。 –

0

运行负荷OPS您可以复制FragmentStatePagerAdapter和你喜欢的更改,或从头开始创建自己的PagerAdapter。或者干脆不要使用Loader。

+0

这不是适配器的问题,它只是在进行交易。但有人花费了相当大的力气来阻止onLoadFinished中的交易提交。我想知道为什么?我也不喜欢为了一行而重写类而且我喜欢Loader概念并想使用它。正如我所说 - 我确实有工作实施直接使用AsyncTask – Bostone

+4

显然是因为调用'onLoadFinished()'时有可能失去状态。从JavaDoc:'请注意,通常应用程序不允许在此调用中提交片段事务,因为它可能在保存活动状态后发生。有关这方面的进一步讨论,请参阅FragmentManager.openTransaction()。 '你必须改变适配器才能使用'commitAllowingStateLoss()'或者取消加载器。我遇到了同样的问题,下面是我得到的答案:https://groups.google.com/forum/#!topic/android-developers/dXZZjhRjkMk/discussion –

0

它的工作原理使用rootView.post()。只需在类作用域中定义rootView变量,然后将其充注到onCreateView()。 最后onLoadFinished()简单地使用这样的:

  rootView.post(new Runnable() { 
       public void run() { 
        General.showFragment(); 
       } 

      });