I can't restore my fragment !
I'm saving like :
#Override
public void onSaveInstanceState(Bundle savedInstanceState)
{
if(cameraFragment != null && cameraFragment.isAdded())
getSupportFragmentManager().putFragment(savedInstanceState, "cameraFrameLayout", cameraFragment);
super.onSaveInstanceState(savedInstanceState);
}
and restoring in onCreate(savedInstanceState) :
if(savedInstanceState == null)
cameraFragment = CameraFragment.newInstance();
else
cameraFragment = (CameraFragment) getSupportFragmentManager().findFragmentByTag("cameraFrameLayout");
When I change the device orientation I can successfully see that the onSaveInstanceState in called with my fragment but on the onCreate I have a null instance...
Txs for help !
You need to restore the saved fragment in onRestoreInstanceState
public void onRetoreInstanceState(Bundle inState){
cameraFragment = getFragmentManager().getFragment(inState,"cameraFrameLayout");
}
Also notice that getFragment is called to the FragmentManager instead if findFragmentByTag. Hope it helps!
Note: call super methods in onSaveInstanceState and onRestoreInstanceState overrides
In your fragment onCreate() method write setRetainInstance(true);
In the Activity that creates the fragment you should do something like this
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null)
{
// Display the fragment as the main content.
getFragmentManager().beginTransaction()
.replace(android.R.id.content, CameraFragment.newInstance())
.commit();
}
}
The android.R.id.content can be different in your case. This is where you want to load your fragment.
Related
I was wondering, what is the Fragment lifecycle methods, I should commit FragmentTransaction to avoid famous
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
According to http://www.androiddesignpatterns.com/2013/08/fragment-transaction-commit-state-loss.html, it gives great tip, on how to avoid such exception, by commit FragmentTransaction
FragmentActivity
onCreate()
onResumeFragments()
onPostResume()
Fragment
???
However, how about Fragment? What is the suitable Fragment lifecycle we should commit our fragment? For instance, under very rare situation, I will get exception from Google Play Console crash report, while trying to commit Fragment in another Fragment's onCreate.
public class BuyPortfolioFragment extends Fragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final FragmentManager fm = this.getFragmentManager();
// Check to see if we have retained the worker fragment.
this.statusBarUpdaterFragment = (StatusBarUpdaterFragment)fm.findFragmentByTag(STATUS_BAR_UPDATER_FRAGMENT);
if (this.statusBarUpdaterFragment == null) {
this.statusBarUpdaterFragment = StatusBarUpdaterFragment.newInstance();
this.statusBarUpdaterFragment.setTargetFragment(this, 0);
// java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
fm.beginTransaction().add(statusBarUpdaterFragment, STATUS_BAR_UPDATER_FRAGMENT).commit();
} else {
statusBarUpdaterFragment.setTargetFragment(this, 0);
}
p/s I know I can avoid such exception by using commitAllowingStateLoss. I want to use it as last resource.
Fragment's lifecycle state not always matches Activity's. Fragment's method getFragmentManager() returns the FragmentManager of it's hosting Activity (unless it's a child Fragment, if so this method returns the child fragment manager of a hosting Fragment). You may never know in which state is Fragment's hosting Activity unless you make tracking code. So it's really possible that the transaction eventually may be committed after Activity onSaveInstanceState() was called.
I suggest using getChildFragmentManager() and deal with child fragments from fragments.
Or if your intention was really to control Activity Fragments, make accessors for controlling it's state, like
// Activity method
public void showSomeFragment() {
if (mFragmentTransactionsAllowed) {
// do transaction
}
}
// And track the boolean
#Override
protected void onCreate(Bundle b) {
super.onCreate(b);
// override on onCreate() in case if Activity object is reused and state was true
mFragmentTransactionsAllowed = true;
}
#Override
protected void onStart() {
super.onStart();
// override here so that if activity goes foreground but not yet destroyed
mFragmentTransactionsAllowed = true;
}
#Override
protected void onResume() {
super.onResume();
mFragmentTransactionsAllowed = true;
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mFragmentTransactionsAllowed = false;
}
I have a few CheckBox elements inside one of my Fragments.
Every time I leave this Fragment it seems to nor save or restore the checked state of each one provided by the user.
In the FragmentList example you can find:
CheckBox check1;
boolean active;
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean("state1", check1.isChecked());
}
Which you can use later like this:
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (savedInstanceState != null) {
// Restore last state for checked position.
check1.setChecked(savedInstanceState.getBoolean("state1"));
}
}
But somehow the CheckBox elements don`t save their state.
Is this the correct approach I should take?
Unless you're keeping your Fragment reference alive through the lifecycle of the application, it should be fine to save its state in onSaveInstanceState and restore it in onActivityCreated.
One important point, though, is also to save and restore that state in the Activity level by doing like:
public void onCreate(Bundle savedInstanceState) {
...
if (savedInstanceState != null) {
// Restore the fragment's instance
mFragment = getSupportFragmentManager().getFragment(
savedInstanceState, "fragKey");
...
}
...
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// Save the fragment's instance
getSupportFragmentManager().putFragment(outState, "fragKey", mContent);
}
Please check to see how your Activity is behaving in your scenario.
I created a test application using AndroidStudio, selecting an activity with a fragment. What I do not understand is how the PlaceholderFragment is restored when savedInstanceState is not null, taking into account that setContentView is called after super.onCreate().
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
getFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment())
.commit();
}
}
Hello the savedInstanceState is only not null when you rotated the device. When the activity recreate it should load from savedInstanceState. by the way the code you are talking about is part of android activity not android studio. Thank you.
I have 2 serializable objects that I want to retain after my fragment is rebuilt. Therefore I saved them during onSaveInstanceState (the objects are not null here):
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable(RENDERER, renderer);
outState.putSerializable(SERIES, series);
}
In the onCreate method of the fragment I try to get them out of the Bundle:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
renderer = (DefaultRenderer) savedInstanceState.getSerializable(RENDERER);
series = (CategorySeries) savedInstanceState.getSerializable(SERIES);
}
}
The problem is that "renderer" and "series" are always null after calling getSerializable. Any ideas why?
Did you override onSaveInstanceState method in FragmentActivity that hosts this fragment? If you're, then make sure that it should call super.onSaveInstanceState(Bundle).
I have a Working model of fragments, when i was debugging the code i saw that the Fragment onCreate is being called 4 times.
Below is my code:
MyFragmentActivity
class MyFragmentActivity extends FragmentActivity{
#Override
public void onCreate(Bundle savedInstanceState) {
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction().replace(fragmentID, new MyListFragmentt())
.replace(detailFragmentID, new MyDetailFragment()).commit();
}
}
#Override
protected void onRestart() {
getSupportFragmentManager().beginTransaction().replace(detailFragmentID, new MyDetailFragment()).commitAllowingStateLoss();
}
}
MyDetailFragment.class
class MyDetailFragment extends Fragment{
// has method like oncreate(),onCreateView(),onSaveInstanceState()
}
How my oncreate of MyDetailFragment is called ? When i go to some other activity and come back and then tilt the device only then oncreate and onSaveInstanceState of MyDetailFragment is called multiple times.
How can i solve this, i have looked into few posts on SO but it says that we need use HIDE,Show methods and other things ? but What is the proper soultion to this ?
EDIT
When i am coming back from previous activity, my data in the MyDetailFragment needs to be refreshed.
Try this
MyDetailFragment fragment = new MyDetailFragment();
#Override
public void onCreate(Bundle savedInstanceState) {
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction().replace(fragmentID, new MyListFragmentt())
.replace(detailFragmentID, fragment).commit();
}
}
#Override
protected void onRestart() {
if(fragment != null) {
getSupportFragmentManager().beginTransaction().replace(detailFragmentID, fragment).commitAllowingStateLoss();
}
}
i think ur recreating fragments multiple times, u do new MyListFragment everytime on onCreate function, call findFragmentByTag to get the existing fragment and set that, if null (first time) then create one
/here is some code mate, if this doesnt work and ur app has single fragment better to just create xml and have only a fragment tag in it, and set that xml in setContentView function*/
// declare following member variable
MyFragment _fragment;
// in onCreate function, call this method
private void setupFragment()
{
_fragment = (MyFragment)getFragmentManager().findFragmentByTag("MyFragment");
if(null == _fragment)
{
_fragment = new MyFragment();
}
// now do the fragment transaction
FragmentTransaction trans = getFragmentManager().beginTransaction();
trans.add(containerId, _fragment, "MyFragment"); // here tag is important
trans.commit();
}