bart bart - 3 months ago 11
Java Question

Simple code throws IllegalStateException when device's orientation changed

Wait app for start. Rotate device. Click on view. Exception.

Project code here

Why do am I getting this exception?

MainActivity.cs

[Activity (Label = "OrientationChangeFragmentCommit", MainLauncher = true, Icon = "@mipmap/icon")]
public class MainActivity : Activity
{
const string currentFragmentTag = "currentFragment";

protected override void OnCreate (Bundle savedInstanceState)
{
base.OnCreate (savedInstanceState);

SetContentView (Resource.Layout.Main);

if (GetCurrentFragment() == null)
{
BlueFragment frag = new BlueFragment();
frag.AuthTcs.Task.ContinueWith(task =>
{
try
{
RunOnUiThread(() => FragmentManager.PopBackStackImmediate());
}
catch (Exception exc)
{
//exception here
}
});
AddFrag(this, frag, Resource.Id.fragmentContainer);
}
}

void AddFrag(Activity act, Fragment frag, int containerId)
{
FragmentTransaction fragmentTx = act.FragmentManager.BeginTransaction();
fragmentTx.Add(containerId, frag, currentFragmentTag);
fragmentTx.AddToBackStack(null);
fragmentTx.Commit();
}

Fragment GetCurrentFragment()
{
var f = FragmentManager.FindFragmentByTag (currentFragmentTag);
return f;
}
}


BlueFragment.cs

public class BlueFragment : Fragment
{
public TaskCompletionSource<bool> AuthTcs = new TaskCompletionSource<bool>();
public override void OnCreate (Bundle savedInstanceState)
{
base.OnCreate (savedInstanceState);
RetainInstance = true;
}

public override View OnCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
base.OnCreateView (inflater, container, savedInstanceState);

var view = new LinearLayout (inflater.Context);
view.Orientation = Orientation.Vertical;
view.SetBackgroundColor (Color.Blue);
ViewGroup.LayoutParams par = new ViewGroup.LayoutParams (ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.MatchParent);
view.LayoutParameters = par;
view.AddView(new View(inflater.Context));

view.Click += (s, e) =>
{
AuthTcs.TrySetResult(true);
};

return view;
}
}


Main.axml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@+id/fragmentContainer"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>


Exception says: Java.Lang.IllegalStateException: Can not perform this action after onSaveInstanceState

Answer

The right code is:

frag.AuthTcs.Task.ContinueWith(task =>
    {
        RunOnUiThread (() => frag.Activity.FragmentManager.PopBackStackImmediate ());
    });

Because lambda function was storing the reference to an old activity, and therefore to an old FragmentManager.

Comments