I am working on a tablet application with two fragments on the main activity. The left fragment is a list fragment whose contents is updated when the user selects a tab or selects an item from 2 spinners within the ActionBar.
Originally I handled orientation change by overriding onConfigurationChanged. As this is not advised by Google and it causes issues with ActionBarSherlock, I have started work on doing it the right way. I have set my fragments to retain their instance (setRetainInstance) for orientation changes.
The problem is when the orientation changes the OnCreate method for the activity adds the tabs to the actionbar and selects one causing the list to reload. This also happens with the spinners as on rotation a new item is selected. On orientation change the list fragment has no need to refresh.
I know it is possible to save the tab and spinner state but how do I stop the list from updating as this is done in the onTabSelected and onItemSelected methods?
How about using onRetainNonConfigurationInstance() to save some state which should not change on orientation change? For example, if you follow #ThomasKJDK's answer , you could set the boolean in this method. You could then retrieve this boolean in onCreate(); and decide on execution of various code segments based on this boolean.
More details about this approach here.
I don't know if this is the proper way of doing it, but you could make a local variable (boolean) which is set after the first OnCreate and reset at OnPause/OnDestroy. You can then use the created variable to exclude execution of some code segments in the onCreate method.
Related
I have a 3-tab ViewPager with custom Fragments (EntryFragment and CalendarFragment; the third is not relevant to the question). Now when I click a date on CalendarFragment the EntryFragment should load up with data of the new date (I have coded it this way).
Now, what happens is something strange: The TextFields in EntryFragment get changed to the new data from the new date. But the Seekbars, Spinners, Switches, etc retain data from their previous date.
I am using the following methods to set the values of the various Views:
seekbar.setProgress(int);
spinner.setSelection(int, false);
switch.setChecked(boolean);
Also, I have attached onItemSelectedListerners for these components. These are getting called automatically after onCreateView() of EntryFragment.
Could anyone guide me why this is happening? Or how to prevent it?
I'm guessing it might be restoring previous state, ViewPagers have inbuilt mechanism to restore views that had been hidden. Your data is set to correct values and restored to previous state after that. To prevent that, try to add saveEnabled=false in xml layout of views you are having problem with.
I'm going mad soon, been reading Google search results for 10+ hours soon, without any luck.
I think i will drop this whole idea of using a spinner and just use tabs, but it still irritates me that i haven't found a solution. So i hope anyone could help me to understand this issue.
The project im creating has one MainActivityContainer (the main FrameLayout), and than multiple fragments (different layouts) that gets first added and than replaced inside the MainActivityContainer.
So the app only opens ONE activity and than changes pages through different fragments. This makes it super fast to change pages.
Everything except for the ActionBar Spinner works great. It doesnt get updated when pressing the back button, i.e it is still displaying the value for the last fragment.
I want to use the spinner so i easily can navigate between different fragments.
The app start page look something like this:
http://1drv.ms/1jkJpy2
The spinner items are:
1. home , 2. ImageBtn1, 3. ImageBtn2, etc.
So i can reach each destination by either clicking the image button or using the spinner. This is the functionality that i want.
But if i click imagebutton (instead of using the spinner) the value in the spinner (home) does not change to ImageBtn1. So even though i am on the page for ImageBtn1 the spinner shows "Home".
I fixed this by using actionBar.setSelectedNavigationItem(1); in the method for the ImageButton. So imagebuttons uses the spinners methods manually. This sets the spinner to the correct value even if pressing the imagebutton on the start page.
This all works well until i press the back button. Than i have the same problem again, the spinners value doesnt update.
So please explain to me how i can solve this. In other words: How to use a spinner actionbar with ONE activity and many fragments and still get the back button to update the spinner. I have began experimenting with the onBackPressed() method. But there has to be an easier way to achieve what i want to do???
Ok I figured out how to update the navigation spinner in the action bar!
In my problem, I always called actionBar.setSelectedNavigationItem(int); inside the onCreate() method of the activity. However, onCreate() is only called when first making a new activity. So whenever I pressed the back button, the onCreate() doesnt get called and the navigation spinner doesn't get updated. However, the onResume() function always gets called when an activity becomes visible to the user (whether the activity was just created or whether the user pressed the back button into it). So I simply called actionBar.setSelectedNavigationItem(int) in onResume() and the navigation spinner now updates whenever the user presses back!.
However, since you are using one activity with multiple fragments, you should probably put your actionBar.setSelectedNavigationItem(int) inside the onResume() of your fragments instead of the activity. And that should work!
I guess this is a good case for really learning and internalising the activity and fragment lifecycles. Back to more learning for me :).
I was wondering if you managed to find a solution? I have a similar problem to you.
In the activity, inside the onBackPressed() method, try calling getSupportFragmentManager().findFragmentByTag(TAG); where TAG is a string that you can give when adding each of the frames (have a different TAG for each fragment).
So in code, when you are putting the fragment in:
getSupportFragmentManager().beginTransaction().add(R.id...., new MyFragment(), "TAG1");
Then the onBackPressed method would look like:
#Override
public void onBackPressed() {
MyFragment myFragment = (MyFragment)getSupportFragmentManager().findFragmentByTag("TAG1");
if (myFragment.isVisible()) {
getActionBar().setSelectedNavigationItem(int);
}
}
Let me know if that works!
NEVER use NAVIGATION_MODE_LIST and onNavigationItemSelected it is not worth it !
#Override
public boolean onNavigationItemSelected(int position, long itemId)
You also cannot use menu's to do this:
#Override public boolean onCreateOptionsMenu(Menu menu)
{
getMenuInflater().inflate(R.menu.activity_main, menu);
due to inflation ordering.
Reasons:
(1) it generates a "hidden" spinner, for which you can not get the id.
(2) you cannot customize this spinner
(3) you save 30 lines of code, but are permanently limited if you want to add a second bi-directional spinner
(4) not even in the special case of "simple code" (one spinner), you lose to much.
(5) you cannot use tabs.
(6) without the id, you have no chance with fragments.
the key is actionBar.setCustomView(R.layout.action_bar_custom);
and spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener()...
for each spinner.
Trust me I lost hours trying each solution.
I have a question. This is possible to call onSavedInstanceState() and onRestoreInstanceState() manually. I need that because I want to recreate all Activity but I want to save last all views. This is schema: I have in activity three toggle buttons, I check all buttons and click on button refresh. Now I want to recreate all views and save all states my buttons and other layouts. Something like onConfigChange() but without changing orientation.
I know you can use this: android:configChanges="orientation" to eliminate redraws on orientation changes. Although it does not in my app. I've read that there may be a method you need to override with it to make it work. But I think that may be overkill.
There are only two issues I do not want to happen when I rotate the screen from portrait to landscape (or the other way).
If the user touches an EditText, keyboard pops up. You shift orientations, and it auto-hides. I want to keep the soft keyboard along for the ride.
I have a ListView loading data populated from a MySQL database. It does this through an AsynTask. When I switch orientations, I do not want this task to be called.
Can I isolate these two issues, or is the first option (configChanges) the answer?
Note: A couple of these are List Activities; but the big one is a FragmentActivity with Viewpager, and a Fragment / ListFRagment (with tabs) inner class inside.
When the orientation changes the Activity is destroyed and recreated. The method you would override if using configChanges is onConfigurationChanged.
For the keyboard question, sounds like you just need to keep a track of it's state and restore it via the Bundle passed in Activity.onCreate.
For the second question, you could check if onSavedInstanceState == null to determine if you need to run the AsyncTask. You will need to save any data to the Bundle in onPause.
I have a FragmentActivity which hosts a FragmentStatePagerAdapter. The pager contains multiple instances of the same fragment, in order that the user can swipe between the items in a list. I want to be able to provide the user with an options menu which will act only on the visible item.
For example, I have a list of images displayed in imageviews inside fragments. I want an option menu item allowing the user to set the image as their wallpaper.
At the moment when I try this, when onPrepareOptionsMenu is called, the code is called in multiple fragments (usually the current + next one). The same when an item is selected. This causes the wrong image to be set as the wallpaper.
How can I prevent the options menu triggering for more than the currently visible fragment?
My solution was to use the setOnPageChangeListener method of the ViewPager in order to keep track of which Fragment index was currently visible with the onPageSelected callback. You still have to get the initial index yourself, but in my case this was trivial
You can intercept the options menu callback in the activity's onOptionsItemSelected, and explicitly call the item from the correct fragment there, returning true to indicate that you've handled it.
The trick is to change sethasoptions( true|false) on each fragment before populating menu. This already helped me