내 조각에 대한 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%28%29
따라서 내 관점에서 올바른 코드는 다음과 같아야합니다.
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);
}
}
}
답변
편집 : 버그는 아니지만 조각 프레임 워크의 결함이 더 많습니다. 이 질문에 대한 더 나은 대답은 위의 @Arcao가 제공 한 것입니다.
—- 원본 게시물 —-
실제로 지원 패키지 의 알려진 버그 입니다 (편집 : 실제로 버그가 아닙니다. @ alex-lockwood의 의견 참조). 버그 보고서의 주석에 게시 된 해결 방법은 다음과 같이 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에 알리는 방법이 있습니다. unregisterPasswordEnteredListener를 적절하게 호출하는 것이 매우 중요합니다 (위의 경우 PlayerListFragment가 “종료”되는 경우). 그렇지 않으면이 대화 상자 조각이 해당 리스너가 더 이상 존재하지 않을 때 등록 된 리스너에서 함수를 호출하려고 할 수 있습니다.
답변
@Natix 가 남긴 댓글 은 일부 사람들이 삭제했을 수있는 빠른 한 줄입니다.
이 문제에 대한 가장 간단한 해결책은 코드를 실행하기 전에 super.onActivityResult () 를 호출 하는 것입니다. 이것은 지원 라이브러리를 사용하는지 여부에 관계없이 작동하며 활동에서 행동 일관성을 유지합니다.
다음이 있습니다.
- 스레드, 핸들러 또는 휴면을 사용하여 가짜 지연 을 추가 할 필요가 없습니다 .
- 상태 손실 또는 하위 클래스가 show ()를 재정의 할 수 있도록 커밋 할 필요가 없습니다 . 버그가 아니라 경고입니다. 상태 데이터를 버리지 마십시오. ( 또 하나 , 보너스 예 )
- 활동에서 대화 조각을 추적 할 필요가 없습니다 (안녕하세요 메모리 누수!).
- 그리고 하나님에 의해 onStart ()를 수동으로 호출하여 활동 수명주기를 망칠 필요가 없습니다 .
내가 이것에 대해 더 많이 읽을수록 내가 본 더 미친 해킹.
여전히 문제가 발생하는 경우 Alex Lockwood 가 확인해야합니다.
- 그럴 필요합니다 onSaveInstanceState ()에 대한 코드를 쓸 ( 또 다른 하나를 )
답변
Android 버그라고 생각합니다. 기본적으로 Android는 활동 / 조각 수명주기 (onStart () 이전)의 잘못된 지점에서 onActivityResult를 호출합니다.
버그는 https://issuetracker.google.com/issues/36929762 에서보고됩니다.
기본적으로 Intent를 나중에 onResume ()에서 처리 한 매개 변수로 저장하여 해결했습니다.
[편집] 요즘에는 2012 년에는 사용할 수 없었던이 문제에 대한 더 나은 솔루션이 있습니다. 다른 답변을 참조하십시오.
답변
편집 : 또 다른 옵션, 그리고 아마도 최고 (또는 적어도 지원 라이브러리가 기대하는 것 …)
Android 지원 라이브러리와 함께 DialogFragments를 사용하는 경우 FragmentActivity의 하위 클래스를 사용해야합니다. 다음을 시도하십시오.
onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, intent);
//other code
ProgressFragment progFragment = new ProgressFragment();
progFragment.show(getActivity().getSupportFragmentManager(), PROG_DIALOG_TAG);
// other code
}
FragmentActivity 의 소스 를 살펴본 결과 상태를 잃지 않고 조각을 재개하기 위해 내부 조각 관리자를 호출하는 것 같습니다.
여기에 나열되지 않은 솔루션을 찾았습니다. Handler를 만들고 Handler에서 대화 조각을 시작합니다. 따라서 코드를 약간 편집하십시오.
onActivityResult(int requestCode, int resultCode, Intent data) {
//other code
final FragmentManager manager = getActivity().getSupportFragmentManager();
Handler handler = new Handler();
handler.post(new Runnable() {
public void run() {
ProgressFragment progFragment = new ProgressFragment();
progFragment.show(manager, PROG_DIALOG_TAG);
}
});
// other code
}
이것은 나에게 더 깨끗하고 덜 해커 보인다.
답변
두 가지 DialogFragment 쇼 () 방법은 – show(FragmentManager manager, String tag)
와 show(FragmentTransaction transaction, String tag)
.
FragmentManager 버전의 메서드를 사용하려는 경우 (원래 질문에서와 같이) 쉬운 해결책은이 메서드를 재정의하고 commitAllowingStateLoss를 사용하는 것입니다.
public class MyDialogFragment extends DialogFragment {
@Override
public void show(FragmentManager manager, String tag) {
FragmentTransaction ft = manager.beginTransaction();
ft.add(this, tag);
ft.commitAllowingStateLoss();
}
}
show(FragmentTransaction, String)
이 방법을 재정의 하는 것은 원래 DialogFragment 코드 내의 일부 내부 변수도 수정해야하기 때문에 쉽지 않으므로 권장하지 않습니다. 해당 메서드를 사용하려면 허용 된 답변 (또는 Jeffrey Blattman).
commitAllowingStateLoss를 사용하는 데는 약간의 위험이 있습니다. 문서에는 “Commit ()과 유사하지만 활동의 상태가 저장된 후 커밋이 실행되도록 허용합니다. 활동이 나중에 해당 상태에서 복원되어야하는 경우 커밋이 손실 될 수 있으므로 위험합니다. 이므로 UI 상태가 사용자에게 예기치 않게 변경 되어도 괜찮은 경우에만 사용해야합니다. “
답변
onSaveInstanceState () 메서드를 호출 한 연결된 활동 후에는 대화 상자를 표시 할 수 없습니다. 분명히 onSaveInstanceState ()는 onActivityResult () 전에 호출됩니다. 따라서이 콜백 메서드 OnResumeFragment ()에서 대화 상자를 표시해야합니다. DialogFragment의 show () 메서드를 재정의 할 필요가 없습니다. 이것이 당신을 도울 것입니다.