提问者:小点点

显示来自onActivityResult的对话片段


我的onActivityResult中有以下代码用于我的片段:

onActivityResult(int requestCode, int resultCode, Intent data){
   //other code
   ProgressFragment progFragment = new ProgressFragment();  
   progFragment.show(getActivity().getSupportFragmentManager(), PROG_DIALOG_TAG);
   // other code
}

但是,我收到以下错误:

Caused by: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState   

有人知道发生了什么,或者我如何解决这个问题吗?我应该注意到我正在使用Android支持包。


共3个答案

匿名用户

如果你使用Android支持库,onResume方法不是正确的地方,在哪里玩片段。你应该在onResumeFragments方法中完成,参见onResume方法描述:http://developer.android.com/reference/android/support/v4/app/FragmentActivity.html#onResume()

所以从我的角度来看,正确的代码应该是:

private boolean mShowDialog = false;

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data){
  super.onActivityResult(requestCode, resultCode, data);

  // remember that dialog should be shown
  mShowDialog = true;
}

@Override
protected void onResumeFragments() {
  super.onResumeFragments();

  // play with fragments here
  if (mShowDialog) {
    mShowDialog = false;

    // Show only if is necessary, otherwise FragmentManager will take care
    if (getSupportFragmentManager().findFragmentByTag(PROG_DIALOG_TAG) == null) {
      new ProgressFragment().show(getSupportFragmentManager(), PROG_DIALOG_TAG);
    }
  }
}

匿名用户

@Natix留下的评论是一些人可能已经删除的一句话。

这个问题最简单的解决方案是在运行您自己的代码之前调用super. onActivityResult()。无论您是否使用支持库,这都有效,并保持Activity中的行为一致性。

有:

  • 无需使用线程、处理程序或睡眠添加虚假延迟。
  • 不需要提交允许状态丢失或子类覆盖show()。这不是bug,而是警告。不要丢弃状态数据。(另一个额外的例子)
  • 无需跟踪活动中的对话框片段(你好,内存泄漏!)
  • 上帝保佑,无需手动调用onStart()来扰乱活动生命周期。

我读得越多,我看到的疯狂黑客就越多。

如果你仍然遇到问题,那么亚历克斯·洛克伍德的那个就是要检查的。

  • 无需为onSaveInstanceState()编写任何代码(另一个)

匿名用户

编辑:不是bug,更多的是片段框架的不足。这个问题更好的答案是上面@Arcao提供的。

----原始帖子----

实际上,这是一个已知的支持包bug(编辑:实际上不是bug。参见@alex-lockwood的评论)。bug报告的评论中发布的一个方法是修改DialogFragment的来源,如下所示:

public int show(FragmentTransaction transaction, String tag) {
    return show(transaction, tag, false);
}


public int show(FragmentTransaction transaction, String tag, boolean allowStateLoss) {
    transaction.add(this, tag);
    mRemoved = false;
    mBackStackId = allowStateLoss ? transaction.commitAllowingStateLoss() : transaction.commit();
    return mBackStackId;
}

请注意,这是一个巨大的黑客攻击。我实际做的方式只是制作我自己的对话框片段,我可以从原始片段中注册。当另一个对话框片段做了一些事情(比如被解雇)时,它告诉任何听众它正在消失。我是这样做的:

public static class PlayerPasswordFragment extends DialogFragment{

 Player toJoin;
 EditText passwordEdit;
 Button okButton;
 PlayerListFragment playerListFragment = null;

 public void onCreate(Bundle icicle){
   super.onCreate(icicle);
   toJoin = Player.unbundle(getArguments());
   Log.d(TAG, "Player id in PasswordFragment: " + toJoin.getId());
 }

 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle icicle){
     View v = inflater.inflate(R.layout.player_password, container, false);
     passwordEdit = (EditText)v.findViewById(R.id.player_password_edit);
     okButton = (Button)v.findViewById(R.id.ok_button);
     okButton.setOnClickListener(new View.OnClickListener(){
       public void onClick(View v){
         passwordEntered();
       }
     });
     getDialog().setTitle(R.string.password_required);
     return v;
 }

 public void passwordEntered(){
   //TODO handle if they didn't type anything in
   playerListFragment.joinPlayer(toJoin, passwordEdit.getText().toString());
   dismiss();
 }

 public void registerPasswordEnteredListener(PlayerListFragment playerListFragment){
   this.playerListFragment = playerListFragment;
 }

 public void unregisterPasswordEnteredListener(){
   this.playerListFragment = null;
 }
}

所以现在我有一种方法来通知PlayerListFragment当事情发生时。请注意,适当地调用unregsterPasswordEnteredListener非常重要(在上面的情况下,当PlayerListFragment“消失”时),否则当该侦听器不再存在时,此对话框片段可能会尝试调用已注册侦听器上的函数。