popBackStack, вызывающий java.lang.IllegalStateException: не может выполнить это действие после onSaveInstanceState - PullRequest
0 голосов
/ 01 декабря 2018

Я получаю эту ошибку ниже в строке manager.popBackStack.Это можно обойти?Это происходит довольно часто.

public void updateView(Fragment fragment) {

        IFragment currentFragment = (IFragment)fragment;

        FragmentManager manager = getSupportFragmentManager();
        FragmentTransaction fragmentTransaction = manager.beginTransaction();
        fragmentTransaction.replace(R.id.content_frame, fragment);

        if(currentFragment != null)
        {
            if(currentFragment.isRoot())
            {
                manager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
            }
            else
            {
                fragmentTransaction.addToBackStack("test");
            }
        }

        fragmentTransaction.commitAllowingStateLoss();

        if(drawerManager.DrawerLayout != null) {
            drawerManager.DrawerLayout.closeDrawer(drawerManager.DrawerList);
        }
    }

Неустранимое исключение: java.lang.IllegalStateException: не удается выполнить это действие после onSaveInstanceState в android.support.v4.app.FragmentManagerImpl.checkStateLoss (FragmentManager.java: 2044) в android.support.v4.app.FragmentManagerImpl.enqueueAction (FragmentManager.java:2067) в android.support.v4.app.FragmentManagerImpl.popBackStack (FragmentManager.java:799) в com.exposure.activities.updateView (BaseActivity.java:239) на com.exposure.activities.events.EventActivity.setupEvent (EventActivity.java:204) на com.exposure.activities.events.EventActivity.getData (EventActivity.java:117) на com.exposure.utilities.ActivityContainer.getData (ActivityContainer.java:83) в com.exposure.utilities.DataTask.onPostExecute (DataTask.java:37) в android.os.AsyncTask.finish (AsyncTask.java:695) в android.os.AsyncTask.-wrap1 (неизвестный источник) на android.os.AsyncTask $ InternalHandler.handleMessage (AsyncTask.java:712) на android.os.Handler.dispatchMessage (Handler.java:105) в android.os.Looper.loop (Looper.java:164) в android.app.ActivityThread.main (ActivityThread.java:6938) в java.lang.reflect.Method.invoke (метод.java) на com.android.internal.os.Zygote $ MethodAndArgsCaller.run (Zygote.java:327) на com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1374)

Ответы [ 3 ]

0 голосов
/ 04 декабря 2018

проблема в основном такова:

IllegalStateException: Невозможно выполнить это действие после onSaveInstanceState.

, поэтому проверьте с !isFinishing() && !isDestroyed() в.updateView()

, потому что это вернет true после onSaveInstanceState() ...

, так что эту ситуацию можно смягчить и предотвратить аварию.

0 голосов
/ 05 декабря 2018

Как объяснено в Потеря состояния транзакций и активности фрагмента под маркером "Избегать выполнения транзакций внутри методов асинхронного обратного вызова" :

Избегайте выполнения транзакций внутри методов асинхронного обратного вызова. Это включает в себя часто используемые методы, такие как AsyncTask#onPostExecute() и LoaderManager.LoaderCallbacks#onLoadFinished().Проблема с выполнением транзакций в этих методах заключается в том, что они не знают о текущем состоянии жизненного цикла Activity, когда они вызываются.

Похоже, это проблема, которая возникает у вас с updateView()вызывается из асинхронной задачи, но давайте проверим эту гипотезу.

Следующее демонстрационное приложение создает фрагмент, имитирует фоновую обработку и обратный вызов, который имитирует ваш асинхронный обратный вызов.В коде есть флаг: mFixIt, когда установлено значение true, приложение ведет себя должным образом (не взрывается), а если значение false, приложение перестает работать.

С mFixIt == false.Триггер - это кнопка «Домой», которая переводит приложение в состояние остановки:

enter image description here

Вот трассировка стека:

14967-15003 E/AndroidRuntime: FATAL EXCEPTION: Thread-2
    Process: com.example.illegalstatepopbackstack, PID: 14967
    java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
        at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:2080)
        at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:2106)
        at android.support.v4.app.FragmentManagerImpl.popBackStack(FragmentManager.java:832)
        at com.example.illegalstatepopbackstack.MainActivity.updateView(MainActivity.java:70)
        at com.example.illegalstatepopbackstack.ui.main.MainFragment$1.run(MainFragment.java:63)
        at java.lang.Thread.run(Thread.java:764)

Теперь с mFixIt == true.Разница на этот раз в том, что приложение распознает асинхронный обратный вызов, когда действие находится в остановленном состоянии, записывает, что это произошло, и завершает обработку при перезапуске приложения.Визуал - это просто нажатие кнопки «Домой» и восстановление из «последних».Приложение просто вставляет фрагмент в начале, а при повторном запуске изменяет верхний текст TextView и извлекает фрагмент из backstack.

enter image description here

Как видно, обработка завершается, как и ожидалось.

Это тривиальный пример.Если ваша обработка более сложна или вы просто хотите более формально справиться с этой ситуацией, я рекомендую взглянуть на это решение .

Вот код для демонстрационного приложения:

MainActivity.java

public class MainActivity extends AppCompatActivity {
    // Set to true to fix the problem; false will cause the IllegalStateException
    private boolean mFixIt = false;

    private MainFragment mFragment;
    private TextView mTextView;
    private boolean mIsPaused;
    private boolean mUpdateViewNeeded;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main_activity);
        mTextView = findViewById(R.id.textView);

        FragmentManager fm = getSupportFragmentManager();
        if (savedInstanceState == null) {
            // Create out fragment
            mFragment = MainFragment.newInstance();
            fm.beginTransaction()
                .replace(R.id.container, mFragment)
                .addToBackStack(FRAGMENT_TAG)
                .commit();
        } else {
            // Find the restored fragment.
            mFragment = (MainFragment) fm.findFragmentByTag(FRAGMENT_TAG);
        }
    }

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

        // Simulate a background task that does something useful. This one just waits a few
        // second then does a callback to updateView(). The activity will be fully paused by then.
        mFragment.doSomethingInBackground();
        mIsPaused = true;
        Log.d("MainActivity","<<<< stopped");
    }

    @Override
    protected void onStart() {
        super.onStart();
        mIsPaused = false;
        if (mUpdateViewNeeded) {
            // Execute delayed processing now that the activity is resumed.
            updateView(getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG));
        }
    }

    public void updateView(Fragment fragment) {
        if (mIsPaused && mFixIt) {
            // Delay processing
            mUpdateViewNeeded = true;
        } else {
            // Do out update work. If we are paused, this will get an IllegalStateException. If
            // we are resumed, this will work as intended.
            mTextView.setText("Replaced...");
            getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
            mUpdateViewNeeded = false;
        }
    }

    public static final String FRAGMENT_TAG = "MyFragment";
}

MainFragment.java

public class MainFragment extends Fragment {

    MainActivity mMainActivity;

    public static MainFragment newInstance() {
        return new MainFragment();
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.main_fragment, container, false);
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        mMainActivity = (MainActivity) context;
    }

    @Override
    public void onDetach() {
        super.onDetach();
        mMainActivity = null;
    }

    @Override
    public void onStart() {
        super.onStart();

    }

    public void doSomethingInBackground() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (mMainActivity != null) {
                    mMainActivity.updateView(MainFragment.this);
                }
            }
        }).start();
    }
}

main_activity.xml

<TextView
    android:id="@+id/textView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@android:color/holo_blue_light"
    android:gravity="center"
    android:text="To be replaced..."
    android:textSize="36sp"
    android:textStyle="bold" />

<FrameLayout
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" />

main_fragment.xml

<android.support.constraint.ConstraintLayout 
    android:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/holo_green_light"
    tools:context=".ui.main.MainFragment">

    <TextView
        android:id="@+id/message"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="MainFragment"
        android:textSize="36sp"
        android:textStyle="bold"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>
0 голосов
/ 04 декабря 2018

Просто вызовите popBackStackImmediate () , так как обычный popBackStack () является асинхронным ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...