Fighting Two Specific Issues on Screen Orientation Change (Android) - android

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.

Related

OnScreenRotation with RecyclerView in tabbed Activity

I am using a tabbed Activity. In one of the tabs I have two buttons and a Recyclerview. In the RecyclerView I have two spinners and an edittext.
The purpose of the first button is to add a new item in the RecyclerView and the second one is to save the chosen elements in the spinners and edittexts.
My problem is that when the screen is rotated, the Recyclerview is emptied. I tried using the OnSaveInstanceState() and the OnRestoreInstanceState of the LayoutManager of the Recyclerview to save the state but it still gets deleted.
I'd appreciate any help !
By default, activities and fragments have an onSaveInstanceState() method that the system uses to provide a Bundle to which you can write primitive data and parcelable objects.
This is okay as long as your data is simple. In your case, it isn't.
The framework may decide to destroy or re-create a UI controller in response to certain user actions or device events that are completely out of your control.
For example screen rotation (orientation change).
ViewModel comes to the rescue.
ViewModel is a class that’s part of the Android Architecture Components and it is lifecycle aware.
For more check this documentation.

How to update controls in all tabs created using FragmentPagerAdapter?

I have created a tabbed android application using android.support.v4.view.PagerAdapter.
There are about seven tabs in the application and I plan to add more. Each tab contains a lot of controls (TextView, Spinners, Toggle buttons, Check boxes etc.)
On the first tab there is a drop down to select a profile. The user can 'Load' or 'Save' a profile he wants.
A profile contains data for all the controls in the tabs and I need to update the UI controls in all the tabs.
I have all the data loaded from the profile but the UI controls are not getting updated.
There is a 'UpdateUI' function which calls 'set' functions (setText, setChecked etc. for individual controls after finding its view by ID).
I was informed that only three tabs (Previous, Current and Next) are kept in memory so I wrote the application such that the 'UpdateUI' function is called to set UI data only when user swipes to that particular tab (figuring out the active fragment).
Using DDMS logs I saw that the data loaded was proper but the 'setText' or 'setXXXXX' function does not update the fragment tab.
I have also checked several possible issues:
Possibility of 'OnTextChanged' or an 'OnListener' updating the data again.
Made sure 'UpdateUI' is called from UI thread.
Using notify data change and redrawing UI to make sure UI is updated.
I am a novice Java/Android programmer. Please point me in the right direction.
viewpager.setOffscreenPageLimit(size);
you can instantiate all your fragments by setting limit then you can update all widgets inside other fragments.
If my understanding of Android Fragment management is right, once the fragment becomes invisible for user (say some other fragment completely overlayed it or in your case you change tabs) Fragment goes through onPause and possible onStop lifecycle stages, this mean it's kind of hybernated and can't be changed before it get's visible. viewpager.setOffsetPageLimit(size) tells the fragment manager (or rather pageAdapter) how many fragments should be kept hybernated, and I doubt it playing with this will change anything, but let me know if it's, because otherwise the solution may be more complicated.
What I'd do is recreate a fragment every time user gets to see it and pass your profile data to it's constructor (or following better practice newInstance() static method), it will in fact save memory since keeping many fragments there may be overwhelming. Alternatively you can check what profile is chosen everytime fragment is calling it's onResume, and update your controls there.

How are inflated layouts recycled in onCreate(), etc?

I have an interface that has two dynamic parts, one of which is more complicated than the other. I had to spend some time with Bundles and onSaveInstanceState(), etc., in order to preserve the state of the first part when the orientation is changed.
Then I turned to do the same with the second, simpler part, and right away noticed that I did not have to do certain things. The layout for this part is inflated in onCreate(), and it contains TextViews and EditTexts whose content can change. This content is retained, but dynamic changes to the layout are not.
When onCreate() is called by restarting the app from the home screen, the changes are not retained.
I have to implement continuity properly via the Bundle anyway, since what is not retained is the state of an object created in onCreate() corresponding to the view. That, and the fact that the behavior is not consistent (restart from homescreen vs. orientation change) make it hard to see this as a "feature", since it implies inflating a "fresh" layout from XML may not always provide a genuinely fresh layout that corresponds exactly to R.layout.whatever.
I'm also guessing this can happen in the context of an Activity's visible lifetime, not just in onCreate(). So what are the rules here?
This content is retained, but dynamic changes to the layout are not
Retaining user-mutable content of common widgets, like the text entered into an EditText, is automatic, from the built-in implementation of onSaveInstanceState(). However, "views... removed from and added to it" (from a previous edition of your question) is definitely not retained by onSaveInstanceState(), and if you re-inflate the layout, such changes definitely will be lost.
When onCreate() is called by restarting the app from the home screen, the changes are not retained.
Well, that will depend upon whether or not the process is still around and whether or not this activity was on the back stack.
So what are the rules here?
If the user is returning to a specific instance of your activity (configuration change, or starting a fresh process from the recent-tasks list), your saved instance state is applied to the new activity instance that is created.
If the user is starting a fresh process without returning to a specific instance of your activity (e.g., home screen launcher), there is no saved instance state to apply.

How to use EditText from a single fragment across tabs?

I'm having difficulty understanding the lifecycle of my fragment when the same fragment is created across three tabs. The main widget in each fragment is an EditText object that that is tracked in a class I created, one per tab, created when my app first executes. When the app executes the input (which is provided by buttons on the screen, not a keyboard) sets text into the second tab's EditText.
The input appears to be following getItem() inside my FragmentPagerAdapter. I understand that getItem() is called twice when my tabs are created and that this is perfectly normal behavior but what I'm not understanding is if this is a focus issue or a logic issue with my code design (I'm hoping the former). Could it have to do with instantiate() being returned by getItem()? Once instantiate() is called, does focus always follow it since I have this line of code in the onCreateView() of my fragment?
active.editLine = (EditText) v.findViewById(R.id.display);
// active is the currently active object of my app's class.
The reason I suspect instantiate() is causing my error is because when I increased the rendering of pages via setOffscreenPageLimit(2) the text was being sent to the third tab.
At this point I tried to track what was happening where and it was a nice educational exercise. What I found in my struggles was this is probably a focus issue-- however my attempts at clearing focus and setting focus did not appear to be applied, nor am I even sure if that's the underlying issue. I ended up using active.editLine.debug(0) to see if focus was being lost or gained and it wasn't. I read some of this fairly popular post and took my focus out of my XML but that didn't help either.
Just to make sure, where should I be setting my EditText objects? In OnCreateView() in my fragment? That is where the above code currently lives. I create three objects of my custom class in my activity as global variables. I have getters and setters in what I feel are appropriate areas of my code. Should the above code instead live in onCreate() of my fragment? If you think this is a focus issue, what is the accepted method of turning off focus and only using it when I need it? More importantly, when my app first runs, where do I turn on focus? OnTabSelected() is called before getItem() runs twice to render the first two tabs. So where would I gain initial focus if I'm globally turning it off? Can set focus with a type of listener?
Not exactly sure what you're going for here, but here are some suggestions:
have your global active object live in the main activity and call getActivity().someObject from your fragments
findViewById() will search down the view hierarchy until it finds the first instance of R.id.display
your fragment views won't be available until you commit them with a fragment transaction, this means that their views also won't be available until that time
you are "scoping" findViewById() to some view v by calling v.findViewById()
if you are paging through fragments, perhaps try setting your active view in the fragment's onResume() method
the fragment's onCreateView() method is only called once. This will be called between onCreate(Bundle) and onActivityCreated(Bundle).

Android actionbar orientation change quirks - calling tabSeleceted & ItemSelected methods

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.

Categories

Resources