Ошибка при транзакции фрагмента из обработчика намерений

Я пытаюсь написать простой музыкальный плеер и столкнулся с такой проблемой. В моем пользовательском интерфейсе у меня есть несколько фрагментов, используемых для разных режимов отображения песен (например, вся музыка, музыка из выбранной папки, музыка из плейлиста и т. Д.). Также у меня есть сервис, который играет музыку.

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

Для сохранения состояния я использую свою Service , упомянутую выше. В onDestroy() моей деятельности я помещаю все необходимые данные для восстановления в намерение и вызываю startService(intent) . Служба сохраняет эти данные в локальные переменные. В onCreate() моей активности я вызываю startService с намерением, содержит запрос сохраненного состояния. В службе я помещаю сохраненные данные в намерение и отправляю их в Activity используя LocalBroadcastManager.getInstance(this).sendBroadcast(intent) . Во внутреннем классе BroadcastListener моей Activity я получаю это намерение и извлекаю данные. Кажется, все в порядке.

Но проблемы возникают, когда я пытаюсь восстановить Fragments которые отображались, когда пользователь закрывал плеер. Сбой приложений с unhandled exception. Вот задняя часть:

 java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1377) at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1395) at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:637) at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:616) at com.borune.test.MainActivity.switchFragments(MainActivity.java:58) at com.borune.test.MainActivity$MyServiceListener.onReceive(MainActivity.java:102) at android.support.v4.content.LocalBroadcastManager.executePendingBroadcasts(LocalBroadcastManager.java:297) at android.support.v4.content.LocalBroadcastManager.access$000(LocalBroadcastManager.java:46) at android.support.v4.content.LocalBroadcastManager$1.handleMessage(LocalBroadcastManager.java:116) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:136) at android.app.ActivityThread.main(ActivityThread.java:5032) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:515) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601) at dalvik.system.NativeStart.main(Native Method) 

Я искал это исключение, но все предлагаемые решения в моем случае не помогли. Я написал простой проект, повторяющий описанную проблему. Вот код:

MainActivity.java :

 public class MainActivity extends ActionBarActivity { private int current_fragment; private FragmentA fragmentA = null; private FragmentB fragmentB = null; private MyServiceListener myServiceListener; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); current_fragment = 1; switchFragments(null); myServiceListener = new MyServiceListener(); LocalBroadcastManager.getInstance(this).registerReceiver(myServiceListener,new IntentFilter(MyService.RESPONSE_RESTORE)); requestState(); } public void switchFragments(View view) { switch(current_fragment) { case 1 : { if(fragmentA == null) { fragmentA = FragmentA.newInstance(); } FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); transaction.replace(R.id.container, fragmentA); current_fragment = 1; transaction.commit(); current_fragment = 2; break; } case 2 : { if(fragmentB == null) { fragmentB = FragmentB.newInstance(); } FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); transaction.replace(R.id.container, fragmentB); current_fragment = 1; transaction.commit(); current_fragment = 1; break; } } } protected void onDestroy(){ super.onDestroy(); Log.d("log", "onDestroy() called, saving fragment number"); Intent intent = new Intent(this,MyService.class); intent.setAction(MyService.SAVE_STATE); intent.putExtra(MyService.FRAGMENT_NUMBER,current_fragment); startService(intent); } private class MyServiceListener extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if(action.equals(MyService.RESPONSE_RESTORE)) { current_fragment = intent.getIntExtra(MyService.FRAGMENT_NUMBER,-1); Log.d("log", "received fragment number, restoring now"); switchFragments(null); } } } private void requestState() { Intent intent = new Intent(this,MyService.class); intent.setAction(MyService.REQUEST_RESTORE); startService(intent); } } 

MyService.java

 public class MyService extends Service { public static final String REQUEST_RESTORE = "action.REQUEST_RESTORE"; public static final String RESPONSE_RESTORE = "action.RESPONSE_RESTORE"; public static final String SAVE_STATE = "action.SAVE_STATE"; public static final String FRAGMENT_NUMBER = "FRAGMENT_NUMBER"; private int fragment_number = -1; public MyService() { } @Override public IBinder onBind(Intent intent) { return null; } @Override public int onStartCommand(Intent intent, int flags, int startId) { String action = intent.getAction(); if(action.equals(REQUEST_RESTORE)) { if(fragment_number != -1) sendState(); } else if (action.equals(SAVE_STATE)) { fragment_number = intent.getIntExtra(FRAGMENT_NUMBER,-1); } return START_NOT_STICKY; } private void sendState() { Intent intent = new Intent(RESPONSE_RESTORE); intent.putExtra(FRAGMENT_NUMBER,fragment_number); LocalBroadcastManager.getInstance(this).sendBroadcast(intent); } } 

В этом приложении у меня есть макет с контейнером и Button с android:onClick="switchFragments" . После закрытия приложения и открытия его снова я получаю то же исключение.

Может кто-нибудь объяснить мне, почему эта ошибка возникает и как ее решить?

Этот поток объяснит, что происходит: получение исключения «IllegalStateException: не удается выполнить это действие после onSaveInstanceState»

Короткий ответ, но может быть опасным: используйте commitAllowingStateLoss() вместо commit() , но он может сломать что-то, если вы не будете осторожны.

Что я сделал, я создал булевский флаг под названием «isSafeToCommitFragment», по умолчанию задал значение false, а затем присвоил значение жизненному циклу Activity следующим образом:

  • OnDestroy (): false
  • OnPause (): false
  • OnResume (): false
  • OnStart (): false
  • OnStop (): false
  • OnPostResume (): true

Перед вызовом функции fragmentTransaction.commit() отметьте флаг следующим образом:

 if (isSafeToCommitFragment) { fragmentTransaction.commit(); } 
Intereting Posts