1

Basically i tried doing a fragment transaction inside a background thread, and i get can't perform this action after onSavedInstanceState. This is what i have done:

I have an activity with two fragments, Fragment A (Contains UI all elements) and Fragment B(contains progress bar) . When the activity is created fragment A is added so the user sees UI elements(Buttons and Edittexts). Then when a button is clicked in Fragment A, (1) a background task is started in the parent activity, and (2) Fragment A is replaced with Fragment B. All this works fine.

But when the task is finished if the task was successful i would like to start a new activity and if it fails i want the current fragment to be replaced with the original one. I have no problem with starting the activity, but when i try to do the fragment transaction, the app crashes saying can't perform this action after onSavedInstanceState.

I did a lot of research on this and found a lot of useful things here, here, but i still haven't been able to solve my problem. The first link is a question on SO, one of the answers was to shift calling the fragment transaction to the onResume method of the activity, but i don't know how to do this. Also i tried using commitAllowingStateLoss and the app still crashes, but the logcat says Activity has been destroyed.

Note: If there is no configuration change, everything runs smoothly.

Here is my Code:

Containing Activity

    public class MainActivity extends FragmentActivity  {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Log.i("tag", "mainActivity onCreate");  
    Fragment taskf =getSupportFragmentManager().findFragmentByTag("taskfrag");

    //Put the Fragment A if Fragment B is not showing
    if(savedInstanceState == null){
    if(taskf == null){
        Log.i("tag", "MainFragment added"); 
        FragmentTransaction fragmentTransaction=   getSupportFragmentManager().beginTransaction();
        fragmentTransaction.add(R.id.wrapper, new MainFragment() ,   "mainfrag").commit();
    }
    }
}

//Fragment B is added here
public void addFragment(){
    Log.i("tag", "fragment added");
    this.getSupportFragmentManager().beginTransaction().replace(R.id.wrapper, new   TaskFragment(), "taskfrag").commit();       

}

// My dummy Task
public void startTask(){
    Log.i("tag", "start Task");
    new Thread(new Runnable() {

        @Override
        public void run() {
            // TODO Auto-generated method stub
             for (int i = 0; i < 100; i++) {
                    Log.i("tag", "publishProgress(" + i + "%)");
                    SystemClock.sleep(100);
                  }

                        getSupportFragmentManager().beginTransaction().replace(R.id.wrapper, new MainFragment(),   "mainfrag").commitAllowingStateLoss();

        }


    }).start();

}

 }

Fragment A

    public class MainFragment extends Fragment {

View fView;
ProgressBar bar;
TextView textView;
Button button;
@Override
public void onCreate(Bundle savedInstanceState) {
    Log.i("tag", "onCreate in Main Fragment "); 
    super.onCreate(savedInstanceState);
    setRetainInstance(true);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    Log.i("tag", "onCreate View in Mainfragment");  
    fView = inflater.inflate(R.layout.mainfragment, container, false);
    textView = (TextView) fView.findViewById(R.id.textview);

    button = (Button) fView.findViewById(R.id.button);

    //Button Click Listener 
    button.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View arg0) {
            Log.i("tag", "button clicked"); 

            ((MainActivity)getActivity()).startTask();
            ((MainActivity)getActivity()).addFragment();

        }
    });
    return fView;
}

   }

Fragment B

    public class TaskFragment extends Fragment{

View fview;
ProgressBar bar;

@Override
public void onCreate(Bundle savedInstanceState) {
    Log.i("tag", "TaskFragment Created");   
    super.onCreate(savedInstanceState);
    setRetainInstance(true);

}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    Log.i("tag", "onCreateView in TaskFragment");   
    fview = inflater.inflate(R.layout.progressfragment, container, false);
    bar = (ProgressBar) fview.findViewById(R.id.sendingSmsProgress);
    return fview;
}


}

Thanks.

Community
  • 1
  • 1
bibi_bryan
  • 371
  • 3
  • 17
  • why do you use another fragment to display only progressbar ? I suggest you to use progressbar in same fragment and make it visible and invisible. – Ketan Ahir Mar 15 '14 at 09:49
  • But if I add a progress dialog inside the fragment, won't it get dismised when there is a configuration change... – bibi_bryan Mar 15 '14 at 10:10
  • which type of config change ? are talking about orientation ? – Ketan Ahir Mar 15 '14 at 10:17
  • Yes and others...what if the activity needs to be recreated for some reason, the fragment would automatically be reloaded, is there a way of tell it to reload it to the state where the progress bar is visible? – bibi_bryan Mar 15 '14 at 10:21
  • try to use android:configChanges="" in manifest.xml so activity will not recreate when config change. – Ketan Ahir Mar 15 '14 at 10:23
  • I've read many people advocating against using onConfigChanges, would give it a try, still...wish there was a better way... – bibi_bryan Mar 15 '14 at 10:45

0 Answers0