我的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支持包。
如果你使用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中的行为一致性。
有:
我读得越多,我看到的疯狂黑客就越多。
如果你仍然遇到问题,那么亚历克斯·洛克伍德的那个就是要检查的。
编辑:不是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“消失”时),否则当该侦听器不再存在时,此对话框片段可能会尝试调用已注册侦听器上的函数。