Java.lang.IllegalStateException: не удается выполнить это действие после onSaveInstanceState с помощью DialogFragment
Я столкнулся с проблемой с DialogFragment/getSupportFragmentManager/Android версии 4.x
01-10 19:46:48.228: E/AndroidRuntime(9879): java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
01-10 19:46:48.228: E/AndroidRuntime(9879): at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1314)
01-10 19:46:48.228: E/AndroidRuntime(9879): at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1325)
01-10 19:46:48.228: E/AndroidRuntime(9879): at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:548)
01-10 19:46:48.228: E/AndroidRuntime(9879): at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:532)
01-10 19:46:48.228: E/AndroidRuntime(9879): at android.support.v4.app.DialogFragment.show(DialogFragment.java:127)
01-10 19:46:48.228: E/AndroidRuntime(9879): at com.v1.mypck.TermsAndConditions.showDialog(TermsAndConditions.java:256)
01-10 19:46:48.228: E/AndroidRuntime(9879): at com.v1.mypck.TermsAndConditions.handleMessage(TermsAndConditions.java:62)
01-10 19:46:48.228: E/AndroidRuntime(9879): at com.v1.mypck.TermsAndConditions$IncomingHandler.handleMessage(TermsAndConditions.java:53)
01-10 19:46:48.228: E/AndroidRuntime(9879): at android.os.Handler.dispatchMessage(Handler.java:99)
01-10 19:46:48.228: E/AndroidRuntime(9879): at android.os.Looper.loop(Looper.java:137)
01-10 19:46:48.228: E/AndroidRuntime(9879): at android.app.ActivityThread.main(ActivityThread.java:4441)
01-10 19:46:48.228: E/AndroidRuntime(9879): at java.lang.reflect.Method.invokeNative(Native Method)
01-10 19:46:48.228: E/AndroidRuntime(9879): at java.lang.reflect.Method.invoke(Method.java:511)
01-10 19:46:48.228: E/AndroidRuntime(9879): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
01-10 19:46:48.228: E/AndroidRuntime(9879): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
01-10 19:46:48.228: E/AndroidRuntime(9879): at dalvik.system.NativeStart.main(Native Method)
В приведенном ниже коде, когда я нажимаю его, он пытается закончить текущую активность и вернуться к предыдущему действию, которое выдает выше ошибки.
Код работает хорошо в старой версии (до 4.x).
Может ли кто-нибудь вести меня в правильном направлении.
public class TermsAndConditions extends SherlockFragmentActivity implements LoaderManager.LoaderCallbacks<JSONObject>{
static final String TAG = "TermsAndConditions";
private static int titleResource;
private static int messageResource;
private IncomingHandler handler = null;
private static final int SHOW_NETWORK_DIALOG = 3;
static class IncomingHandler extends Handler {
private final WeakReference<TermsAndConditions> mTarget;
IncomingHandler(TermsAndConditions target) {
mTarget = new WeakReference<TermsAndConditions>(target);
}
@Override
public void handleMessage(Message msg) {
TermsAndConditions target = mTarget.get();
if (target != null) {
target.handleMessage(msg);
}
}
}
public void handleMessage(Message msg) {
switch (msg.what) {
case SHOW_NETWORK_DIALOG:
titleResource = R.string.msg_alert_no_network_title;
messageResource = R.string.msg_alert_no_network_message;
showDialog();
break;
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.web_view);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportLoaderManager().initLoader(0, null, this);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
finish();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void loadViewData() {
//Logic to load content.
}
@Override
public Loader<JSONObject> onCreateLoader(int arg0, Bundle arg1) {
if (handler == null){
handler = new IncomingHandler(TermsAndConditions.this);
}
return new JsonLoader(this);
}
@Override
public void onLoadFinished(Loader<JSONObject> arg0, JSONObject jsonData) {
if(jsonDataObject==null || jsonDataObject.length()==0) {
handler.sendEmptyMessage(SHOW_NETWORK_DIALOG);
} else {
loadViewData();
}
}
@Override
public void onLoaderReset(Loader<JSONObject> arg0) {
if(jsonDataObject==null || jsonDataObject.length()==0) {
handler.sendEmptyMessage(SHOW_NETWORK_DIALOG);
} else {
loadViewData();
}
}
public static class JsonLoader extends AsyncTaskLoader<JSONObject> {
public JsonLoader(Context context) {
super(context);
}
@Override
protected void onStartLoading() {
if (jsonDataObject != null) {
deliverResult(jsonDataObject);
}
if (takeContentChanged() || jsonDataObject == null) {
forceLoad();
}
}
@Override
public JSONObject loadInBackground() {
try {
return response.getJSONObject("result");
} catch (JSONException e) {
return null;
} catch (Throwable e) {
return null;
}
}
@Override
public void deliverResult(JSONObject newJsonData) {
if (isReset()) {
if (jsonDataObject != null) {
onReleaseResources(jsonDataObject);
}
}
JSONObject oldData = jsonDataObject;
jsonDataObject = newJsonData;
if (isStarted()) {
super.deliverResult(jsonDataObject);
}
if (oldData != null) {
onReleaseResources(oldData);
}
}
@Override
protected void onStopLoading() {
cancelLoad();
}
@Override public void onCanceled(JSONObject jsonData) {
super.onCanceled(jsonData);
onReleaseResources(jsonData);
}
@Override protected void onReset() {
super.onReset();
onStopLoading();
if (jsonDataObject != null) {
onReleaseResources(jsonDataObject);
jsonDataObject = null;
}
}
protected void onReleaseResources(JSONObject jsonData) {
jsonData = null;
}
}
public static class MyAlertDialogFragment extends DialogFragment {
public static MyAlertDialogFragment newInstance(int title) {
MyAlertDialogFragment frag = new MyAlertDialogFragment();
Bundle args = new Bundle();
args.putInt("title", title);
frag.setArguments(args);
return frag;
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
int title = getArguments().getInt("title");
return new AlertDialog.Builder(getActivity())
.setTitle(title)
.setMessage(messageResource)
.setPositiveButton(R.string.alert_dialog_ok,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
}
}
)
.create();
}
}
public void showDialog() {
DialogFragment newFragment = MyAlertDialogFragment.newInstance(titleResource);
newFragment.show(getSupportFragmentManager(), "my_dialog");
}
}
Ответы
Ответ 1
Вот ответ в другом потоке:
Действия в onActivityResult и "Ошибка Невозможно выполнить это действие после onSaveInstanceState"
также здесь:
Обновление моего фрагмента не работает, как я думал, он должен
Это пример решения этой проблемы:
DialogFragment loadingDialog = createDialog();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.add(loadingDialog, "loading");
transaction.commitAllowingStateLoss();
Ответ 2
У меня такая же проблема, и я изменил код ниже:
newFragment.show(transactionFragment, "dialog");
в
transactionFragment.add(android.R.id.content, newFragment).addToBackStack(null).commitAllowingStateLoss();
завершенный код работает хорошо для меня, как рев, надеюсь, что помощь
FragmentTransaction transactionFragment = getActivity().getSupportFragmentManager().beginTransaction();
DialogPageListFragment newFragment = new DialogPageListFragment();
transactionFragment.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
newFragment.setArguments(extras);
transactionFragment.add(android.R.id.content, newFragment).addToBackStack(null).commitAllowingStateLoss();
Ответ 3
Вероятно, обработчик, который реагирует на HandleMessage, связан с уничтоженным действием.
i.e.: Если вы поворачиваете экран, старое уничтоженное действие будет обрабатывать сообщение, тогда вы вызовете showDialog, и будет выбрано исключение:
Вы создаете диалог после того, как старое уничтоженное действие вызвало его onSaveInstanceState.
Попробуйте заменить обратный вызов новым созданным действием, чтобы убедиться, что вы создаете диалог всегда в активной активности.
Если вы не вращаетесь, поставьте флаг onSaveInstance как "сохранение" и отключите его onRestoreInstance. В методе handleMessage, если флажок "Сохранить" включен, не показывайте диалоговое окно, просто включите еще один флаг, указывающий, что диалог должен быть создан на onResume. Затем в методе onResume проверьте, если в середине этого процесса вы должны создать диалог, если да, покажите его по методу onResume.
Ответ 4
fragmentView.post(() -> {
FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
YourDialog yourDialog = YourDialog.newInstance();
yourDialog.show(ft, "text_data");
});
Цель метода post() в этом случае - дождаться завершения onResume() Activity или Fragment. Это работает, если вы хотите показать DialogFragment from Fragment. Например, когда вы хотите показать свой диалог после закрытия системного диалога.
Ответ 5
Я столкнулся с той же проблемой, когда post delaying Runnables handler.postDelayed(Runnable runnable, long delayed).
Я решил проблему таким образом:
- В onSaveInstanceState я отменяю задержанные задачи
- В onRestoreInstanceState я воссоздаю задачу, если были замедленные задачи, когда активность была уничтожена.
Ответ 6
слишком поздно ответить, но может быть правильным ответом.
Я сделал родительский класс, и фрагмент диалога простирается от него
public class BaseDialogFragment extends DialogFragment {
@Override
public void show(FragmentManager manager, String tag) {
try {
FragmentTransaction ft = manager.beginTransaction();
ft.add(this, tag).addToBackStack(null);
ft.commitAllowingStateLoss();
} catch (IllegalStateException e) {
Log.d("ABSDIALOGFRAG", "Exception", e);
}
}
boolean mIsStateAlreadySaved = false;
boolean mPendingShowDialog = false;
@Override
public void onResume() {
onResumeFragments();
super.onResume();
}
public void 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 = getFragmentManager();
BaseDialogFragment snoozeDialog = new BaseDialogFragment();
snoozeDialog.show(fm, "BaseDialogFragment");
}
}
}
Ответ 7
onPostResume()
используйте метод возобновления работы, чтобы выполнить свою работу.
Я думаю, что вы вызываете метод show dialog в onRestart или onResume, поэтому избегайте его и используйте onPostResume(), чтобы показать свое диалоговое окно.
Ответ 8
Вы можете проверить, является ли текущая активность isActive() и только в этом случае начать транзакцию фрагмента DialogFragment. У меня была аналогичная проблема, и эта проверка решила мой случай.
Ответ 9
Работает:
CheckinSuccessDialog dialog = new CheckinSuccessDialog();
//dialog.show(getSupportFragmentManager(), null);
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(dialog, null);
ft.commitAllowingStateLoss();
Но все же плохо, потому что получена ошибка "Активность была уничтожена"
ava.lang.IllegalStateException: Activity has been destroyed fragmentTransaction.commitAllowingStateLoss();
Итак, мое решение добавляет check if (!isFinishing()&&!isDestroyed())
CheckinSuccessDialog fragment = CheckinSuccessDialog.newInstance();
if (fragment instanceof DialogFragment) {
DialogFragment dialog = (DialogFragment) fragment;
if (!dialog.isAdded()) {
fragmentTransaction.add(dialog,
CheckinSuccessDialog.class.getName());
if (!isFinishing()&&!isDestroyed()) {
fragmentTransaction.commitAllowingStateLoss();
}
}
при увольнении:
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
Fragment fragment = getSupportFragmentManager().findFragmentByTag(CheckinSuccessDialog.class.getName());
if (fragment != null && fragment instanceof DialogFragment) {
DialogFragment dialog = (DialogFragment) fragment;
dialog.dismiss();
if (!isFinishing()&&!isDestroyed()) {
fragmentTransaction.commitAllowingStateLoss();
}
}
Ответ 10
В Деятельности перед отображением диалога вы можете сделать что-то вроде этого
getSupportFragmentManager().executePendingTransactions();
Это сработало для меня.