I am working on an Android app that uses 5 ActionBar tabs to navigate between different pages/fragments.
Problem is, that the navigation between the fragments is causing the UI to hang/flicker.
The UI of the fragments is not dynamic, meaning that it is not build with a static set of controls. When a fragment becomes visible apps starts to load the corresponsing view model, e.g. by loading a set of data from a server. As soon as the model is loaded the UI is generated. Thus showing a fragment includes the following stepps:
Show an inderminante progress bar to indicate the running progress
Start an AsyncTask to do the heavy loading
As soon as the task is complete generate the UI, e.g. insert an ImageView for every loaded image.
Hide the progress bar and show the generated content.
I thought using a background thread to do the loading would avoid any UI hangs but this it not the case. The creation of the UI elements has to be done in the UI thread of course and it seems that this work is causing the UI hangs.
Even if the number of UI elements that have to be create is quite low (e.g. create 10 Buttons) the UI hangs for a moment. Thus using other strategies (e.g. create visible elements only) does not solve the problem.
Only when no UI elements are created at all the navigation between the fragments runs fluently.
How can I solve this?
The only solution I found so far is, not to load the view model / generate the UI when a fragment becomes visible / is created but as soon as the activity is created. In that case I would only show the activity once the view models / views of all fragments have been loaded/generated. But this would mean to load a lot of data without knowing if it will be used at all.
Is there any better solution? Creating UI elements on the fly is not that uncommon, is it? Thus there has to be a way how this can be done without blocking the UI.
Related
Should I just initialise and keep both, and set visibility to VISIBLE or GONE depending on the state? Is there a better method? What about memory issues? I would like to have a RecyclerView and a WebView alternately. I want to avoid Fragments - I tried that already and separation of responsibility between Activity, UI and Fragments is a hell.
I keep my UI (inheriting from AnkoComponent) in a separate class, if that matters.
I tried to implement doing some background calculation using an AsyncTaskLoader, just as I thought would be the right way to do it.
Calculation is done in a different thread, the UI can stay smooth and buttery.
But the opposite happend.
My UI has some sliding panels. The user swipes them open, selects something in there and while the sliding panel slides back into place, the background task is performing its calculations for the main display that is again revealed while the sliding panel moves back.
Now: when the background task is done and AsyncTaskLoader.loadInBackground() is finished, the onLoadFinished callback method of my fragment is triggered - it sets the adapter of the main contents to the new result and triggers notifyDataSetChanged of this adapter.
Whenever my background calculation is FAST, the sliding panel is not yet back in its retracted place and the update of the adapter's data makes the panel movement "hang"!
Thus: by using background tasks, I literally mess up my formerly smooth UI.
How do you guys deal with things like that??
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.
I have a problem with the viewpager navigation. It hangs during the transition from one page to another. (Laggy). You can see above the simplified architecture of my code. I understood that AsyncTask were the problem since these processes communicate with UIThread. My asynctaks update fragment views. So, is it possible both to navigate very smoothly with viewpager and simultaneously update views?
Thanks
Hard to give a specific answer without seeing your code, but :
AsyncTask are only supposed to touch the UI thread in the onPostExecute method, and that should be used to update your UI once the task is complete. You should set a default UI to be shown as soon as your Fragment is created and update the UI when the task is complete. If you can't show any content before getting data from the AsyncTask, you can set the Fragment's view to show a ProgressBar and hide that to show your data when you have it (refer to this question for details).
I hope this helps ;) Let me know if you need more explanation ...
I want a Viewpager that shows loading while content is coming in from the background. Basically I expect the first View to be loaded, but View+1 and View-1 will still be loading. If the user swipes to either side I want them to be presented with a spinning dialog while it loads
Would I just add AsyncTasks into the ViewPager with some conditions determining when they will run? I dont want too many AsyncTasks to be loading as the viewpager will have many views off to the sides.
I think the Trulia app does this, it is similar to what I am looking for. Apartment image viewing shows a loading screen while the images are loading in that viewpage.
Also for the record, can I just treat viewpagers like onCreate functions of an activity? That would really clear things up
Insight appreciated
Have a look at the supplied FragmentPagerAdapter if you want to perform more Activity-like lifecycle management of each page.