I have a TabActivity that hosts other three activities.
If the first tab is selected, I can change the device orientation and everything is ok.
If I go to the second or the third tab and change the orientation, the tab sub activity's(second and third) onCreate() method gets called twice, for the first time is setting the default tab content(the first one) and at the second onCreate, is setting the selected tab content(as it should for the first time).
Why is onCreate() method being called twice and how can I solve the problem?
EDIT:
I don't want to use android:configChanges="orientation" in the manifest because I want to get the app title and system bar down and on portrait to show them, and this is possible only before setting a content...
use the android:configChanges="orientation" attribute in manifest file like below
<activity android:name=".Settings" android:screenOrientation="portrait"
android:configChanges="orientation"></activity>
Just so that I am clear, are you saying that you have several tabs, which are using different orientations (portrait or landscape), and you are having issues when switching tabs and setting the corresponding orientations properly?
In response to Cata's comment:
Yes, so anytime you rotate the screen the currently viewable activity is destroyed and onCreate is called again (if I recall the steps). What you have to do is call getCurrentTab(), which returns the int value representing the tab, and resetting that as the active tab when onCreate is called. You can do this in several ways...either by having a small method that handles just that and calling it via onCreate, or by using onSaveInstanceState(Bundle) to save your current data, and onRestoreInstanceState() to reload your tab data.
You can set a global int (int currentTab = 0), not setting it in onCreate(), and in your onSaveInstanceState(Bundle) method you can save that to the current tab (currentTab = getCurrentTab()), then in onRestoreInstanceState() you can set it again.
Does that make sense?
Keep in mind that I have not tested that, but willing to do so if you aren't familiar with those two method calls.
Below is an example of saving data to the Bundle - also recall that onCreate accepts that activity bundle as a parameter.
#Override
public void onSaveInstanceState(Bundle outState){
// Store UI state to the savedInstanceState.
// This bundle will be passed to onCreate on next call.
super.onSaveInstanceState(outState);
String strMinSec = timer.getText().toString();
String strMs = timerMs.getText().toString();
long curElapstedTime = elapsedTime;
boolean timerStopped = stopped;
int orientation = this.getResources().getConfiguration().orientation;
outState.putString("MinSec", strMinSec);
outState.putString("Ms", strMs);
outState.putLong("Elapsed", elapsedTime);
outState.putBoolean("Stopped", timerStopped);
outState.putInt("Orientation", orientation);
}
#Override
public void onRestoreInstanceState(Bundle savedInstanceState){
// Restore UI state from the savedInstanceState.
if (savedInstanceState != null){
String MinSec = savedInstanceState.getString("MinSec");
if (MinSec != null)
{
timer.setText(MinSec);
}
String Ms = savedInstanceState.getString("Ms");
if (Ms != null)
{
timerMs.setText(Ms);
}
long elapsed = savedInstanceState.getLong("Elapsed");
if(elapsed > 0)
elapsedTime = elapsed;
int theOrientation = savedInstanceState.getInt("Orientation");
//if(theOrientation > 0)
//this.setRequestedOrientation(theOrientation);
}
}
I think the best solution is to take a different approach by using a single Activity and put every tab content in a different LinearLayout and in onClick() methods of the tabs(which will be some buttons) to switch between the layouts...
If anybody have a better idea, please post it here!
Thank you!
Related
I have a activity with multiples initializations ( fragments , sharedpreferences , services , ui components(search bar , buttons etc..)...) and i do not want to restart the activity when the screen orientation change
I found a easy ( and working solution ) by using android:configChanges="keyboardHidden|orientation|screenSize" but my technical manager forbade me this way because according to him it's a bad practice
What are the other ways in order to handle properly the screen orientation changes?
Thank you very much
My main activity
#AfterViews
public void afterViews() {
putSharedPrefs();
initializeFragments();
initializeComponents();
initializeSynchronizeDialog();
initDownloadDialog();
}
You can just add layout for landscape mode.
You just need to add folder layout-land in your "res" directory and define layout for what your activity looks like if it is in landscape mode.
NOTE-Keep xml file name same as the name which is in simple layout folder and which you are using in your activity. It will automatically detect your screen orientation and apply layout accordingly.
EDIT1
Now to save your text from the text view =) Lets assume your textview is named as MyTextView in your layout xml file. Your activity will need the following:
private TextView mTextView;
private static final String KEY_TEXT_VALUE = "textValue";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mTextView = (TextView) findViewById(R.id.main);
if (savedInstanceState != null) {
String savedText = savedInstanceState.getString(KEY_TEXT_VALUE);
mTextView.setText(savedText);
}
#Override
protected void onSaveInstanceState (Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(KEY_TEXT_VALUE, mTextView.getText());
}
Basically, whenever Android destroys and recreates your Activity for orientation change, it calls onSaveInstanceState() before destroying and calls onCreate() after recreating. Whatever you save in the bundle in onSaveInstanceState, you can get back from the onCreate() parameter.
So you want to save the value of the text view in the onSaveInstanceState(), and read it and populate your textview in the onCreate(). If the activity is being created for the first time (not due to rotation change), the savedInstanceState will be null in onCreate(). You also probably don't need the android:freezesText="true"
You can also try saving other variables if you need to, since you'll lose all the variables you stored when the activity is destroyed and recreated.
I'm trying to learn Android Fragments and I have a very specific problem concerning Fragment management, because screen orientation screws up my implementation.
EDIT: Already solved my problem, see the "Update" below.
Short version:
Using static Fragments, if I change screen orientation, the reference to R.id.fragment is lost and the Activity re-creates the Fragment causing problems because another Fragment is still present on the Layout (because they're defined on the XML maybe).
Context:
I have a Master/Detail workflow using the default Eclipse template and I have a different type of Fragment for every tab on the ItemList. Ideally, what I want to do is switch between fragments, but I want to retain their current state without using the BackStack, since I want to navigate with the ItemList, and using the Back button to close the App.
I couldn't find any solutions for this specific problem and I tried with a lot of different approaches. Right now I'm using static fragments defined in the main Layout:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/item_detail_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ItemDetailActivity"
tools:ignore="MergeRootFrame" >
<fragment android:name="com.example.pintproject.DevicesFragment"
android:id="#+id/devices"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent"
/>
<fragment android:name="com.example.pintproject.ItemDetailFragment"
android:id="#+id/detail"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent"
/>
</FrameLayout>
In the ItemListActivity onCreate(), I look for the Fragments in the layout, and add them if they aren't created yet, and I hold a reference to the current active Detail Fragment so I can hide it / show the fragment I switch to.
I'm using hide/show instead of replace because replace destroys the Fragment:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_item_list);
if (findViewById(R.id.item_detail_container) != null) {
// The detail container view will be present only in the
// large-screen layouts (res/values-large and
// res/values-sw600dp). If this view is present, then the
// activity should be in two-pane mode.
mTwoPane = true;
// In two-pane mode, list items should be given the
// 'activated' state when touched.
((ItemListFragment) getSupportFragmentManager().findFragmentById(
R.id.item_list)).setActivateOnItemClick(true);
}
df = (DevicesFragment) getSupportFragmentManager().findFragmentById(R.id.devices);
if (df==null){
df = new DevicesFragment();
getSupportFragmentManager().beginTransaction().add(R.id.item_detail_container,df).commit();
getSupportFragmentManager().beginTransaction().hide(df).commit();
}
idf = (ItemDetailFragment) getSupportFragmentManager().findFragmentById(R.id.detail);
if (idf==null){
idf = new ItemDetailFragment();
getSupportFragmentManager().beginTransaction().add(R.id.item_detail_container,idf).commit();
getSupportFragmentManager().beginTransaction().hide(idf).commit();
}
mContent = df;
#Override
public void onItemSelected(String id) {
if (mTwoPane) {
// In two-pane mode, show the detail view in this activity by
// adding or replacing the detail fragment using a
// fragment transaction.
switch (Integer.valueOf(id)){
case 1:{
if (idf!=null){
getSupportFragmentManager().beginTransaction().hide(mContent).commit();
getSupportFragmentManager().beginTransaction().show(idf).commit();
mContent = idf;
}
}break;
case 2:{
if (df!=null){
getSupportFragmentManager().beginTransaction().hide(mContent).commit();
getSupportFragmentManager().beginTransaction().show(df).commit();
mContent = df;
}
}break;
}
} else {
// In single-pane mode, simply start the detail activity
// for the selected item ID.
Intent detailIntent = new Intent(this, ItemDetailActivity.class);
detailIntent.putExtra(ItemDetailFragment.ARG_ITEM_ID, id);
startActivity(detailIntent);
}
}
Problem:
With this approach, the Fragments hide/show without any problems and hold the status, but if I make an Orientation Change, they are destroyed and recreated again.
I know they are destroyed because I'm not using setRetainInstance(), but the problem is when I change orientation, the Activity loses the reference to the Fragment, and
df = (DevicesFragment) getSupportFragmentManager().findFragmentById(R.id.devices);
is null, so the program creates another Fragment. If I change the orientation again, not only the program re-creates two new Fragments, but two more Fragments are somehow added to the layout and they aren't even hidden, they are shown one above another.
If I use setRetainInstance(), the Fragment holds the state when Orientation is changed, but still, the activity reference to the Fragment is null, and creates a new Fragment above the existing one, having two of each Fragment.
Example:
I create Fragment A and Fragment B in Landscape orientation. Both work fine and I can switch between them.
I change orientation to Portrait, Fragment A and Fragment B are destroyed and a new Fragment A' and Fragment B' are created, still, they work fine.
I change orientation again to Landscape, Fragment A' and Fragment B' are destroyed, a new Fragment A'' and Fragment B'' are created, but the screen shows another Fragment A and Fragment B, both at the same time (one above another, let's call them residual), and these new A'' and B'' work fine but are shown above residual A and B.
From this point on, every time I change orientation, 2 new Fragments are added to the previous ones, but they don't even hold the previous state.
I hope the example is clear enough. I think the problem is the Activity not holding view references when the orientation is changed, creates them again and I don't really know how to work around that.
UPDATE:
I solved my problem by using findFragmentByTag instead of findFragmentById. Since I can now retrieve Fragment s already created, I have to add them to the container adding a specific tag to search for.
So my test code looks like this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_item_list);
if (findViewById(R.id.item_detail_container) != null) {
// The detail container view will be present only in the
// large-screen layouts (res/values-large and
// res/values-sw600dp). If this view is present, then the
// activity should be in two-pane mode.
mTwoPane = true;
// In two-pane mode, list items should be given the
// 'activated' state when touched.
((ItemListFragment) getSupportFragmentManager().findFragmentById(
R.id.item_list)).setActivateOnItemClick(true);
}
df = (DevicesFragment) getSupportFragmentManager().findFragmentByTag("df");
idf = (ItemDetailFragment) getSupportFragmentManager().findFragmentByTag("idf");
if (savedInstanceState==null){
if (df==null){
df = new DevicesFragment();
getSupportFragmentManager().beginTransaction().add(R.id.item_detail_container,df, "df").commit();
getSupportFragmentManager().beginTransaction().hide(df).commit();
}
if (idf==null){
idf = new ItemDetailFragment();
getSupportFragmentManager().beginTransaction().add(R.id.item_detail_container,idf,"idf").commit();
getSupportFragmentManager().beginTransaction().hide(idf).commit();
}
} else {
Log.i("OUT","INSTANCE NOT NULL");
}
mContent = df;
}
This is fully functional, also have to setRetainInstance(true) for every Fragment and they hold their current state no matter how many times we change the orientation.
You must never hold a reference to the fragment. Instead. Whenever you need something from it, retrieve the reference for a short moment.
public ItemListFragment getItemListFragment() {
return ((ItemListFragment) getSupportFragmentManager().findFragmentById(
R.id.item_list));
}
Then, whenever you need to get data from it, use
final ItemListFragment listFragment = getItemListFragment();
if (listFragment != null) {
// do something
}
And avoid calling setters. You can define the setters, but it's a better practice to either pass an arguments when creating a Fragment or retrieve the data by getActivity() from the Fragment itself, as described below.
This is done because the Fragment lifecycle not always matches the Activity one.
If you ever have to call setter from Activity, don't forget to save the value in Fragment's onSaveInstanceState(), if needed.
So instead of calling
setActivateOnItemClick(true);
From Activity, do it from the Fragment.
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final YourActivity activity = (Activtity) getYourActivity();
setActivateOnItemClick(activity.isMultiPane());
}
This way when the Fragment is re-created after Activity onCreate() (only in which you handle the value setting), it will has always access to the value
And define isMultiPane method from Activity, of course
public boolean isMultiPane() {
return mTwoPane;
}
Since there are no answer yet, here is my opinion :
When your orientation changes, your fragment is being recreated and you loose your data, right ? I think this is exactly whete the "savedInstanceState" is made for :
Caution: Your activity will be destroyed and recreated each time the user rotates the screen. When the screen changes orientation, the system destroys and recreates the foreground activity because the screen configuration has changed and your activity might need to load alternative resources (such as the layout).
Here is a link that can explain you how to handle that recreation
Hope this is useful to you ! =)
I have a ViewPager (instantiated with FragmentStatePagerAdapter) with some Fragment attached to it.
In a specific usecase I need to reset instanceBean and UI for most of the fragments in the pager.
After some googling I have tried some solutions like this but the side effects were not easy manageable. Other solution like this doesn't match my needs.
So I decided to go straight with the manual reset of the UI and instanceBean obj like in the code below:
The code
Single fragment reset
public void initFragment() {
notaBean = new NoteFragmentTO();
fromSpinnerListener = false;
}
public void resetFragment() {
initFragment();
NoteFragment.retainInstanceState = false;
}
This is done with the following code from the parent Activity:
Fragment reset from parent
private void resetAfterSaving() {
mIndicator.setCurrentItem(POSITION_F*****);
f*****Info.resetFragment();
mIndicator.setCurrentItem(POSITION_NOTE);
noteInfo.resetFragment();
mIndicator.setCurrentItem(POSITION_M*****);
m*****Info.resetFragment();
mIndicator.setCurrentItem(POSITION_V*****);
v*****.resetFragment();
}
AfterViews method:
#AfterViews
public void afterView() {
if (mSavedInstanceState != null) {
restoreState(mSavedInstanceState);
}
NoteFragment.retainInstanceState = true;
// Inits the adapters
noteAdapter = new NoteArrayAdapter(this, noteDefaultList);
sp_viol_nota_default.setAdapter(noteAdapter);
//sp_viol_nota_default.seton
et_viol_nota.setOnFocusChangeListener(new OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus) {
String readText = et_viol_nota.getText().toString().trim();
notaBean.setNota(readText == "" ? null : readText);
}
}
});
}
OnSavedInstanceState
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelableArrayList(KEY_NOTE_D_LIST, (ArrayList<VlzAnagraficaNoteagente>) noteDefaultList);
outState.putInt(KEY_NOTE_D_POSITION, !NoteFragment.retainInstanceState ? 0 : notePosition);
notaBean.setNota(!NoteFragment.retainInstanceState ? "" : et_viol_nota.getText().toString().trim());
outState.putParcelable(NoteFragmentTO.INTENT_KEY, notaBean);
}
Why do I set every page before resetting them?
Because like explained here:
When pages are not visible to the user, their entire fragment may be destroyed, only keeping the saved state of that fragment.
and because until I don't select the relative fragment the #AfterViews method (that is everything processed right after OnCreateView of the fragment) is not executed.
This throws NullPointerException for a thousand of reason (Usually in the #AfterViews method You launch RestoreState method, initializes adapter, do UI stuff).
Setting the relative page before the reset let #AfterViews method be processed.
Before checking what would happened when rotating the device, all the fragment I need are correcly reset.
When rotating the device, the error comes out:
The views (mainly EditText) go back to their previous state BEFORE my reset.
What happens?
When switching between the page, at a certain point the page will be destroyed and OnSavedInstanceState is called everytime for each page.
I have already handled the OnSavedInstanceState (like above) that when the boolean is false saves the state like if it had just been created.
I found that until within AfterView method the EditText has its text set to blank (like I want) but going on with the debug the EditText goes back to its previous state, so at the end it will show the last text it had.
Question
How can I keep the manually set (in OnSavedInstanceState) EditText text after destroying/recreating a fragment?
Problems with app:
When orientation changes the app is experiencing these problems:
Both FragmentA and FragmentC now occupy the FrameLayout container.
What works: Everything works as I want it to...prior to rotating the screen.
Activity description in brief:
EditActivity Purpose: edit collection and item fields.
Fragments this activity programmatically creates:
FragmentA - fragment for editing collection fields
FragmentB - ListFragment of items in collection
FragmentC - fragment for editing item fields.
Initial layout: FragmentA sits atop FragmentB, each in their own FrameLayouts.
When user clicks FragmentB's listview item: replace FragmentA with FragmentC to allow user to edit that item's fields. Now FragmentC sits atop FragmentB.
This seems like a very simple notion: the top portion of the activity is for editing either properties of the collection as a whole or a single item from the collection. I don't feel I have done anything wondrous with the layout so I'm a fair bit perplexed that a simple rotation of the phone (emulator) causes these problems that I am having such a dastardly time trying to fix.
Why the Android Fragment Guide example doesn't work for me: their example is much like what I am doing but their detail fragment is either being opened in a new activity or in its own Frame within the current activity, they don't do any swapping of fragments so I cannot glean how they would use the onSaveIstanceState to preserve the fragments that are visible and then use that information in onCreate to recreate the UI that was there prior to orientation change.
EDIT: took out one problem by caving and putting the listfragment in the XML, this solved the perpetual spinning "loading..." problem.
Solved. Oh, the rabbit holes I traveled... At any rate, if you run into problems like this a couple of things to consider:
ultimately I didn't have to write any code in onSaveInstanceState(Bundle outState).
Ultimately I didn't have to make any considerations about handling the backstack in onSaveInstanceState or deal with it the activity's onCreate.
When first "adding" fragments programmatically to the FrameLayout, use replace instead of `add' - this was likely one of the roots of my troubles.
in onCreate check if savedInstanceState's bundle is null, if(savedInstanceState == null), and if it is then I know that the activity hasn't been torn down previously by a configuration change, so here I build fragments that should be displayed right at activity start up. Other fragments that are programmatically brought to life elsewhere (ie, later than the activity's onCreate()), they don't belong in the if, they belong in the else:
else onSaveInstanceState != null and I know there's only one reason this thing's not null, because the system made a bundle named outState in onSaveInstanceState(Bundle outState) and hucked it at the activity's onCreate method where I can now get my grubbies on it. So it is here that I know a couple of things:
for sure the fragments I created in the activity's onCreate are still a part of the activity (I didn't detach or destroy them), but, I cannot make that same claim for the fragments brought to life via a user's actions, those fragments may or may not be currently (at the time of orientation aka configuration change) attached to the activity.
This is a good place for an if-this-thing-is-attached clause. One of things I initially messed up on was I failed to give ALL of my programmatically added fragments a tag; give all programmatically added fragments tags. I can then find out if the savedInstanceState bundle contains that key with savedInstanceState.containsKey(MY_FRAG_TAG) and with getFragmentManager().findFragmentByTag(MY_FRAG_TAG)
So here's the activity's onCreate (simplified):
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_edit);
// ...omitted code...
if(savedInstanceState == null){
// create fragment for collection edit buttons
editCollection = FragmentA.newInstance(someVariable);
// programmatically add fragment to ViewGroup
getFragmentManager().beginTransaction().replace(R.id.edit_topFrame, editCollection, EDIT_COLLECTIONS_TAG).commit();
}
// else there be stuff inside the savedInstanceState bundle
else{
// fragments that will always be in the savedInstanceState bundle
editCollectionFragment = (FragmentA)getFragmentManager().findFragmentByTag(EDIT_COLLECTIONS_TAG);
// fragments that may not be in the bundle
if(savedInstanceState.containsKey(EDIT_ITEM_TAG)){
editItemFragment = (FragmentC)getFragmentManager().getFragment(savedInstanceState, EDIT_ITEM_TAG);
}
}
// This fragment is NOT programmatically added, ie, it is statically found in an XML file.
// Hence, the system will take care of preserving this fragment on configuration changes.
listFrag = (ListViewFragment)getFragmentManager().findFragmentById(R.id.ListFragment);
// create adapter
adapter = new EditCursorAdapter(this, null);
// set list fragment adapter
listFrag.setListAdapter(adapter);
// prepare the loader
getLoaderManager().initLoader(LOADER_ID, null, this);
}
And the Activity's listener for the list fragment, where FragmentC is swapped for FragmentA:
// listfragment listener
#Override
public void listFragListener(Cursor cursor) {
// checking backstack size
Log.d(TAG, SCOPE +"backstack size: "+getFragmentManager().getBackStackEntryCount());
// With each listview click there should be only one item in the backstack.
getFragmentManager().popBackStack();
// create new fragment
editItemFragment = FragmentC.newInstance(cursor);
// programmatically add new fragment
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.edit_topFrame, editItemFragment, EDIT_ITEM_TAG);
ft.addToBackStack("pop all of these"); // was testing different ways of popping
ft.commit();
// interesting: this reports the same value as the first log in this method.
// ...clearly addToBackStack(null).commit() doesn't populate the backstack immediately?
Log.d(TAG, SCOPE +"backstack size: "+getFragmentManager().getBackStackEntryCount());
}
And onSaveInstanceState is naked as a jay bird:
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
Summary: I have the activity functioning exactly as I want it to.
Now, if I had a bunch of added fragments then I might handle them in a more programmatic fashion rather than by hard coding the if(savedInstanceState.contains(*hard coded key*). This I tested a little bit but cannot attest to its efficacy, however for someone out there this might spark an idea of what you can do:
Make a private Set of added fragments:
// Collection of Frag Tags
private Set<String> AddedFragmentTagsSet = new HashSet<String>();
In onAttachFragment do something like:
#Override
public void onAttachFragment(Fragment fragment) {
super.onAttachFragment(fragment);
// logging which fragments get attached and when
Log.d(TAG, SCOPE +"attached fragment: " +fragment.toString());
// NOTE: XML frags have not frigg'n tags
// add attached fragment's tag to set of tags for attached fragments
AddedFragmentTagsSet.add(fragment.getTag());
// if a fragment has become detached remove its tag from the set
for(String tag : AddedFragmentTagsSet){
if(getFragmentManager().findFragmentByTag(tag).isDetached()){
AddedFragmentTagsSet.remove(tag);
}
Log.d(TAG, SCOPE +"contents of AddedFragmentTagsSet: " +tag);
}
}
Then in the activity's onCreate and within savedInstanceState clauses:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_edit);
// ...omitted code...
if(savedInstanceState == null){
// create fragment for collection edit buttons
editCollection = FragmentA.newInstance(someVariable);
// programmatically add fragment to ViewGroup
getFragmentManager().beginTransaction().replace(R.id.edit_topFrame, editCollection, EDIT_COLLECTIONS_TAG).commit();
}
// else there be stuff inside the savedInstanceState bundle
else{
// fragments that will always be in the savedInstanceState bundle
editCollectionFragment = (FragmentA)getFragmentManager().findFragmentByTag(EDIT_COLLECTIONS_TAG);
//////////// find entries that are common to AddedFragmentTagsSet & savedInstanceState's set of keys ///////////
Set<String> commonKeys = savedInstanceState.keySet();
commonKeys.retainAll(AddedFragmentTagsSet);
for(String key : commonKeys){
editItemFragment = FragmentC)getFragmentManager().getFragment(savedInstanceState, key);
}
}
}
...but that is untested and presented merely to spark ideas; in trying to figure out what was wrong with my activity's handling of configuration changes I did stumble and fumble in this direction and think it might bear fruit for the right person; though ultimately, obviously, I found a simpler way to fix my issues this time around.
I have 3 fragments in my app divided into 3 tabs respectively [1] [2] [3].
Imagine that I use a button on the fragment [1] that will make a TextView with an initial text "X" becomes a "Y" Ex: tv.setText("I'm a new text");
So when I navigate between tabs and I return to the tab [1], the TextView is back with the original text. It is as if the onCreate() was calling again.
I wish somehow that onStop() was not called in my fragments, retaining all the properties of my views (such as text, visibility etc.) in memory while I swap between tabs.
Thanks!
---- EDIT! ----
Well, I found the solution to what I wanted! It's simple enough I declare that:
mPager = (ViewPager) findViewById(R.id.pager);
mPager.setOffscreenPageLimit(3); //Number of fragments that I wish to store in memory
onCreate method is being called again. You can save the values by overriding onSavedInstanceState and get them back in onActivityCreated method. For example lets save boolean(you can save whatever you want - string, int etc..):
save the value:
public void onSaveInstanceState(Bundle outState) {
outState.putBoolean("booleanValue", true);
}
restore the value (you can call this in onCreate as well):
protected void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (savedInstanceState != null && savedInstanceState.containsKey("booleanValue")) {
boolean myBoolean = savedInstanceState.getBoolean("booleanValue");
}
}
well, that happens because the onCreate is actually being called. If I was you, I would use a ViewPager. That way, just setting the offScreenElementNumber to 2 you'll have all fragments instantly loaded and they will preserve their state!
take a look at this:
http://tamsler.blogspot.com.es/2011/10/android-viewpager-and-fragments.html