일부 사용자는 알림 표시 줄의 빠른 작업을 사용하면 강제 종료됩니다.
“TestDialog” 클래스 를 호출하는 알림에 빠른 작업을 표시합니다 . “snooze”버튼을 누른 후 TestDialog 클래스에서 SnoozeDialog를 표시합니다.
private View.OnClickListener btnSnoozeOnClick() {
return new View.OnClickListener() {
public void onClick(View v) {
showSnoozeDialog();
}
};
}
private void showSnoozeDialog() {
FragmentManager fm = getSupportFragmentManager();
SnoozeDialog snoozeDialog = new SnoozeDialog();
snoozeDialog.show(fm, "snooze_dialog");
}
오류는 *IllegalStateException: Can not perform this action after onSaveInstanceState*.
IllegarStateException이 발생하는 코드 줄은 다음과 같습니다.
snoozeDialog.show(fm, "snooze_dialog");
클래스는 “FragmentActivity”를 확장하고 “SnoozeDialog”클래스는 “DialogFragment”를 확장합니다.
다음은 오류의 전체 스택 추적입니다.
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1327)
at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1338)
at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:595)
at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:574)
at android.support.v4.app.DialogFragment.show(DialogFragment.java:127)
at com.test.testing.TestDialog.f(TestDialog.java:538)
at com.test.testing.TestDialog.e(TestDialog.java:524)
at com.test.testing.TestDialog.d(TestDialog.java:519)
at com.test.testing.g.onClick(TestDialog.java:648)
at android.view.View.performClick(View.java:3620)
at android.view.View$PerformClick.run(View.java:14292)
at android.os.Handler.handleCallback(Handler.java:605)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4507)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:790)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:557)
at dalvik.system.NativeStart.main(Native Method)
이 오류를 재현 할 수 없지만 많은 오류 보고서를 받고 있습니다.
아무도이 오류를 어떻게 해결할 수 있습니까?
답변
이것은 일반적인 문제 입니다. show ()를 재정의하고 DialogFragment 확장 클래스에서 예외를 처리하여이 문제를 해결했습니다.
public class CustomDialogFragment extends DialogFragment {
@Override
public void show(FragmentManager manager, String tag) {
try {
FragmentTransaction ft = manager.beginTransaction();
ft.add(this, tag);
ft.commit();
} catch (IllegalStateException e) {
Log.d("ABSDIALOGFRAG", "Exception", e);
}
}
}
이 메서드를 적용해도 DialogFragment.class의 내부 필드는 변경되지 않습니다.
boolean mDismissed;
boolean mShownByMe;
이로 인해 경우에 따라 예기치 않은 결과가 발생할 수 있습니다. commit () 대신 commitAllowingStateLoss ()를 더 잘 사용하십시오.
답변
당신을 의미 그 commit()
( show()
후 조각 DialogFragment의 경우) onSaveInstanceState()
.
Android는 조각 상태를 onSaveInstanceState()
. 따라서 commit()
조각 후 onSaveInstanceState()
조각화하면 상태가 손실됩니다.
결과적으로 활동이 종료되고 나중에 다시 생성되면 조각이 나쁜 사용자 경험 인 활동에 추가되지 않습니다. 그렇기 때문에 Android는 어떤 대가를 치르더라도 상태 손실을 허용하지 않습니다.
쉬운 해결책은 상태가 이미 저장되었는지 확인하는 것입니다.
boolean mIsStateAlreadySaved = false;
boolean mPendingShowDialog = false;
@Override
public void onResumeFragments(){
super.onResumeFragments();
mIsStateAlreadySaved = false;
if(mPendingShowDialog){
mPendingShowDialog = false;
showSnoozeDialog();
}
}
@Override
public void onPause() {
super.onPause();
mIsStateAlreadySaved = true;
}
private void showSnoozeDialog() {
if(mIsStateAlreadySaved){
mPendingShowDialog = true;
}else{
FragmentManager fm = getSupportFragmentManager();
SnoozeDialog snoozeDialog = new SnoozeDialog();
snoozeDialog.show(fm, "snooze_dialog");
}
}
참고 : 조각이 재개되면 onResumeFragments ()가 호출됩니다.
답변
private void showSnoozeDialog() {
FragmentManager fm = getSupportFragmentManager();
SnoozeDialog snoozeDialog = new SnoozeDialog();
// snoozeDialog.show(fm, "snooze_dialog");
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(snoozeDialog, "snooze_dialog");
ft.commitAllowingStateLoss();
}
참조 : 링크
답변
며칠 후 내 솔루션을 어떻게 수정했는지 공유하고 DialogFragment를 표시하려면 show()
메서드 를 재정의 commitAllowingStateLoss()
하고 Transaction
개체를 호출 해야 합니다. 다음은 Kotlin의 예입니다.
override fun show(manager: FragmentManager?, tag: String?) {
try {
val ft = manager?.beginTransaction()
ft?.add(this, tag)
ft?.commitAllowingStateLoss()
} catch (ignored: IllegalStateException) {
}
}
답변
대화 상자가 실제로 중요하지 않은 경우 (앱이 닫히거나 더 이상 표시되지 않을 때 표시하지 않아도 괜찮음) 다음을 사용하십시오.
boolean running = false;
@Override
public void onStart() {
running = true;
super.onStart();
}
@Override
public void onStop() {
running = false;
super.onStop();
}
그리고 실행 중일 때만 대화 상자 (조각)를 엽니 다.
if (running) {
yourDialog.show(...);
}
아마도 더 나은 솔루션 편집 :
수명주기에서 onSaveInstanceState가 호출되는 경우 예측할 수없는 경우 다음과 같이 isSavedInstanceStateDone ()을 확인하는 것이 더 나은 해결책이라고 생각합니다.
/**
* True if SavedInstanceState was done, and activity was not restarted or resumed yet.
*/
private boolean savedInstanceStateDone;
@Override
protected void onResume() {
super.onResume();
savedInstanceStateDone = false;
}
@Override
protected void onStart() {
super.onStart();
savedInstanceStateDone = false;
}
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
savedInstanceStateDone = true;
}
/**
* Returns true if SavedInstanceState was done, and activity was not restarted or resumed yet.
*/
public boolean isSavedInstanceStateDone() {
return savedInstanceStateDone;
}
답변
나는이 문제에 수년간 뛰어 들었다.
인터넷은 이것에 대한 토론의 수 (수백? 수천?)로 흩어져 있으며, 그 안에있는 혼란과 허위 정보가 많은 것 같습니다.
상황을 더 악화시키기 위해, xkcd “14 표준”만화의 정신으로, 나는 반지에 대한 나의 대답을 던지고 있습니다.
는 cancelPendingInputEvents()
, commitAllowingStateLoss()
, catch (IllegalStateException e)
, 유사한 솔루션과 모든 극악한 보인다.
다음은 문제를 재현하고 수정하는 방법을 쉽게 보여줍니다.
private static final Handler sHandler = new Handler();
private boolean mIsAfterOnSaveInstanceState = true;
@Override
protected void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
mIsAfterOnSaveInstanceState = true; // <- To repro, comment out this line
}
@Override
protected void onPostResume()
{
super.onPostResume();
mIsAfterOnSaveInstanceState = false;
}
@Override
protected void onResume()
{
super.onResume();
sHandler.removeCallbacks(test);
}
@Override
protected void onPause()
{
super.onPause();
sHandler.postDelayed(test, 5000);
}
Runnable test = new Runnable()
{
@Override
public void run()
{
if (mIsAfterOnSaveInstanceState)
{
// TODO: Consider saving state so that during or after onPostResume a dialog can be shown with the latest text
return;
}
FragmentManager fm = getSupportFragmentManager();
DialogFragment dialogFragment = (DialogFragment) fm.findFragmentByTag("foo");
if (dialogFragment != null)
{
dialogFragment.dismiss();
}
dialogFragment = GenericPromptSingleButtonDialogFragment.newInstance("title", "message", "button");
dialogFragment.show(fm, "foo");
sHandler.postDelayed(test, 5000);
}
};
답변
FragmentManager 대신 FragmentTransaction을 사용하십시오. 아래 코드가 문제를 해결할 것이라고 생각합니다. 그렇지 않은 경우 알려주십시오.
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
SnoozeDialog snoozeDialog = new SnoozeDialog();
snoozeDialog.show(ft, "snooze_dialog");
편집하다:
이 링크를 확인하십시오. 나는 그것이 당신의 질문을 해결할 것이라고 생각합니다.