Using AsyncTaskLoaders in Android makes UI bumpy - android

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??

Related

Tab layout transition delay is very fast

Am using custom animations in view pager and these animations works perfectly when swiping left or right,but when pressing on the tabs itself without swiping, the animations is done very fast causing damage to the eye, so is there any function to change the delay when pressing on the tabs ?
The first thing comes to my mind is making delay with a handler but delaying the transition between pages may cause unexpected result because of user behavior like clicking buttons very fast. I recommend making the view pager's transition animation a little slower. You can achieve such a behavior by using the Slowing speed of Viewpager controller in android

Scrolling a ViewPager programmatically, by a small amount

I have the requirement for what is effectively two activities side by side, allowing the user to scroll from one to the other, and back. I've decided that ViewPager is probably the best way to handle this, but am open to suggestions.
When the activity loads, the left hand view is displayed. I want to indicate to the user that the other view exists, by just scrolling it a small amount to the left and back again (similar to the way it's now common to show that a sliding drawer menu exists).
I've tried a number of things but have yet failed to find a method where both the views scroll smoothly together. Another way of interpretting the requirement is saying I want to programmatically fake a user flicking the page briefly.
Try calling the method fakeDragBy(float)! According to the documentation you need to first call beginFakeDrag() to initiate it and then call endFakeDrag(). This will mantain the ViewPagers default snapping behavior, so once you've revealed the other screen is there you don't have to animate the transition back, simply call endFakeDrag and the ViewPager will correctly snap back to the last screen (As long as you haven't dragged it past the half-way mark).

Avoid UI flicker/hangs when navigating through ActionBar tabs

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.

Shouldn't there be an option for Fragments to retain click events within their view hierarchy?

After seeing a couple questions here on SO regarding Fragments "passing" their click events down to clickable Views in underlying Fragments, I recalled that I once encountered this problem. What is actually happening is that if a user clicks on a blank area of the top most Fragment, since its ViewGroup is not clickable, the event will be handled by the clickable View (i.e. Button) that is conveniently placed just below the user's finger. I fixed it by making the top Fragment's ViewGroup clickable. Back then I didn't give it much thought, but this solution seems a bit "hacky".
I understand that it is normal behavior for a View that is non clickable by default to not intercept click events, but one would think that given that one big use for Fragments is to display the view hierarchy (a task done by the Activity only before) that it will resemble an Activity in this sense. When one Activity fires the Intent to create a new Activity, and then this Activity is on the screen, no click events are delivered to the underlying Activity. I realize that an Activity can contain many Fragments that may not fill the whole screen or even have no xml, but sometimes click events are only meant to be retained by the top most Fragment.
With all that said, here come the questions:
1) Is setting the ViewGroup on the top most Fragment to be clickable the best way to solve this?
2) Does this feature exist and I am not aware of it? And if not, should it?
Is setting the ViewGroup on the top most Fragment the best way to solve this?
Assuming that your UI is akin to the UI from the question you linked to, the UI is written improperly.
My take on the UI from that question is that the developer has two fragments, A and B, each of which fill the screen. A is there initially, with the three buttons at the bottom. The developer then calls add() to display B, where B has an opaque black background.
This is dumb on a few levels. Not only do you run into this touch event propagation issue, but you have overdraw problems, because Android is going to render the buttons, then render the black background on top of them.
The right answer here is to have B replace() A.
(I realize that the developer actually does not have a fragment A, but has those widgets in the activity, which adds another level of sketchiness to that UI)
More generally, I would not have fragments, or anything else, higher on the Z axis with the intent to hide underlying widgets. So, for example, having a full-screen VideoView, with a pop-up MediaController higher on the Z axis is fine, because touch events destined for the controller would be picked up by the controller, yet the user can still tap on portions of the VideoView not blocked by the controller. Conversely, I would not implement a tabbed Web browser by having one WebView overlay another WebView on the Z axis -- either there would only be one WebView, or there would only be one visible WebView (with the other removed from the view hierarchy or marked as View.GONE).
When one Activity fires the Intent to create a new Activity, and then this Activity is on the screen, no click events are delivered to the underlying Activity.
That is because there is no "underlying activity" in terms of the view hierarchy. More technically, each activity is in its own Window, and so even if the top-most Window does not fill the screen (e.g., dialog-themed activity), the "underlying activity" is visible but cannot receive touch events.
I realize that an Activity can contain many Fragments that may not fill the whole screen or even have no xml, but sometimes click events are only meant to be retained by the top most Fragment.
Then there should not be anything underneath "the top most Fragment", IMHO. Use replace(), not add(), when doing this sort of UI switch. Or, use a DialogFragment, if you want to temporarily have something modal take over foreground input (as a dialog gets its own Window, if I understand correctly). Do not just paint a solid background and pretend that other widgets, now painted over, do not exist.
Does this feature exist and I am not aware of it?
No, because fragments are not ViewGroups and therefore are not involved in managing the routing of touch events.
And if not, should it?
IMHO, no, though you're welcome to file an issue for it.

Swipe lag issue with Viewpager

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 ...

Categories

Resources