Error while fragment transaction from intent handler

I am trying to write a simple music player and have encountered such a problem. In my user interface, I have several fragments used for different song display modes (for example, all music, music from the selected folder, music from the playlist, etc.). I also have a service that plays music.

When the user closes the player in the playback state, I want to save the state of the user interface (i.e. the current fragment of the display) and restore this state after the player is reopened (if the user closed the player in the pause state, it is not needed).

To save state I use mine Servicementioned above. In the method of onDestroy()my activity, I put all the necessary data for recovery into intention and call it startService(intent). The service stores this data in local variables. In the method of onCreate()my activity, I call startServicewith the intent contains a request for a saved state. In the service, I put the saved data in the intent and send it to Activityusing the method LocalBroadcastManager.getInstance(this).sendBroadcast(intent). In BroadcastListenermy inner class, ActivityI get this intention and retrieve the data. Everything seems to be in order.

But problems arise when I try to restore Fragmentswhich was displayed when the user closed the player. Application crashes using unhandled exception.Here is a stack:

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". .

- , ?

+4
1

, : "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();
}
+5

All Articles