Can anybody explain the meaning of scrolling cache in Android. I stumbled upon this word, but was unable to find the explanation, either on android official website or on the web.
All I could find was how can I turn it on/off.
Thanks.
Scrolling cache is basically a drawing cache.
In android, you can ask a View to store its drawing in a cache called drawing cache (basically a bitmap). By default, a drawing cache is disabled because it takes up memory but you can ask the View to explicitly to create one either via setDrawingCacheEnabled or through hardware layers (setLayerType).
So why is it useful? Because using a drawing cache make your animation smooth compared to redrawing the view at every frame.
This type of animation can also be hardware accelerated because the rendering system can take this bitmap and upload it to the GPU as a texture (if using hardware layers) and do fast matrix manipulations on it (like change alpha, translate, rotation). Compare that to doing animation were you are redrawing (onDraw gets called) on every frame.
In the case of a listview, when you scroll by flinging, you are in essence animating the views of your list (either moving them up or down). The listview uses the drawing cache of its visible children (and some potentially visible children near the edges) to animate them very quickly.
Is there a disadvantage to using drawing cache? Yes it consumes memory which is why by default it is turned off for in a View. In the case of ListView, the cache automatically created for you as soon as you touch the ListView and move a little (to differentiate a tap from scroll). In other words, as soon as ListView thinks you are about to scroll/fling it will create a scroll cache for you to animate the scroll/fling motion.
scrollingCache is explained in full detail in the lecture of "the world of listView".
It's basically caches the scrolling itself so that it will move a bitmap, but according to my experience, it actually makes things much slower and take memory for nothing special.
scrollingCache is enabled by default, at least for listView . That's why if performance is important for you, you should consider disabling it.
I think you are talking about the following:
Imagine a list of 50 items where only 10 items are visible. Android will cache the next and previous (estimate) 5 items in a list item.
When you start scrolling through the list it will reuse the invisible item views, using the ArrayAdapter's function getView()
For example if you are scrolling to the top it will take a view on the bottom and place it on top with new data.
So scrolling cache are the next and previous items above/under the visible items.
official explanation: http://developer.android.com/reference/android/widget/AbsListView.html#attr_android:scrollingCache
Romain Guy's blog about the cache color hint optimization: http://www.curious-creature.org/2008/12/22/why-is-my-list-black-an-android-optimization/
Related
I have a pretty complex android-application. Already flattened view-hierarchies as far as possible, but I still have lags in the application. For example there is a menu with entries that collapse/expand by having their height set by a ValueAnimator. Typically the animation runs with a bit of a lag the first time, and smooth after this first pass.
I noticed that when i call "requestLayout()" on the Menu-Item, Android seems to do a layout-pass and multiple measure-passes through the entire hierarchy.
Since i know that although the Menu-Item(View) changes height, the Menu(View) itself doesn't, is there some way to tell this to the application?
Can i somehow perform this first pass that seems to lag myself so that it occurs after application start-up and not at the first touch-input?
Here's a sketch of the animation I'm doing:
I am not sure why a layout is being triggered in your animation but I am going to answer your question abstractly.
If you are calling requestLayout (either directly or indirectly) in your animation you are doing it WRONG.
requestLayout, for correctness and safety, does a full view traversal on the view hierarchy b/c conceptually changing bounding box of a node in the view hierarchy can result in change in the bounds of any other node. Not always the case but in general it could, thats why requestLayout is a full traversal.
All of this is just another way of saying requestLayout will eat away time from your 16.6 ms frame time slot and make your animation choppy. This is especially bad for deep and complex hierarchies with many RelativeLayouts which internally does two passes per level (thus potentially causing exponential passes on a subtree)
Now, if you want to animate change in dimension use setScale in a hardware layer. And at the end of the animation merrily call requestlayout and also destroy the layer (to free up memory).
Because its a layer, repeatedly calling setScale in your animation results in change of the texture on the GPU and as a result totally bypass the traversal mechanism of the view hierarchy. This should make it buttery smooth.
Your question looks like mine: Only relayout children and not all the tree
First, you can try to avoid complex view hierarchy for your view. If possible, explode views on views that doesn't depend on another one.
When an animation is performed, avoid any layout request. Start your animation with a delay if a layout request is pending.
Use hardware layers for animation if possible (maybe Android use it by default with ValueAnimator)
Without going into too much detail, I want to be able to 'slide' elements in a ListView similar to the 'slide to archive' feature in GMail. I'm fine with the onTouchListener and all that, my question is regarding the slide animation.
The first two things that come to mind are..
view.setPadding(slideOffset, 0, 0, 0);
and..
view.setX(slideOffset);
The former is very buttery, even on the emulator.
The latter is a bit janky on my Galaxy Nexus.
My questions:
* Regardless of what I've tried, what's the correct way to do this?
Why is setX less smooth than setPadding?
Does one approach conform to Android best practices more than the other?
Are tweened translation animations an option? If so, can you provide a brief example to point me in the right direction please?
Edit:
To be clear, I am attaching an image of the effect I am trying to emulate.
I'm pretty sure the setX() is slower because it affects its parents. When changing the X of a view, it calls the onLayout/onMeasure of the parent every time you update the value. That's because the X value of the child may cause other items on the parent to move, therefor the parent needs to redraw itself.
You can test this easily by extending the ViewGroup and writing to the log on those methods. Then, you can use both approaches, padding vs. setX, and see what happens.
Are you trying to animate the item? Or do you want the user to move it like on Gmail? You can use the ObjectAnimator to handle the "X" value of your item. Combined with a "hardware layer" for your item, it will create a smoother experience. You can find more details about how to do that here: http://developer.android.com/guide/topics/graphics/hardware-accel.html
Yeah, if you're targeting higher APIs, ViewPropertyAnimator is probably a great solution. If you have to support lower APIs, my thought process for implementation would be (and I haven't implemented this myself personally, but this should be good for performance) to:
In your touch handler, once you've determined that the user is "sliding", set the View's visibility to INVISIBLE, and store the drawing cache into a separate bitmap (Bitmap bmp = myView.getDrawingCache();)
Draw that bitmap in the same place as the view, and use the Canvas translate methods to shift the position according to the x-position of the user's touch point.
After the user lets go, translate back (preferably smoothly with an animation), recycle the bitmap, and set the view back to VISIBLE.
Check out the 3 devBytes posted on AndroidDev:
https://www.youtube.com/watch?v=8MIfSxgsHIs&list=PLWz5rJ2EKKc_XOgcRukSoKKjewFJZrKV0&index=12
https://www.youtube.com/watch?v=NewCSg2JKLk&list=PLWz5rJ2EKKc_XOgcRukSoKKjewFJZrKV0&index=11
https://www.youtube.com/watch?v=NewCSg2JKLk&list=PLWz5rJ2EKKc_XOgcRukSoKKjewFJZrKV0&index=11
https://www.youtube.com/watch?v=YCHNAi9kJI4&list=PLWz5rJ2EKKc_XOgcRukSoKKjewFJZrKV0&index=4
https://www.youtube.com/watch?v=PeuVuoa13S8&list=PLWz5rJ2EKKc_XOgcRukSoKKjewFJZrKV0&index=3
I'm currently trying to work out how to properly use hardware layers when animating views.
I'm implementing a ViewGroup that enables the user to drag a child view, after which I animate it to a position when they release (like how ViewPager will settle on a page). This article states that you should only enable hardware layers for the duration of the animation.
The issue I'm having is that after hardware layers are enabled Android has to create the layers, which takes 70-100ms on a Galaxy Nexus. This means I can't do it immediately before starting the animation, as having the delay between the drag and the animation would be very noticeable. I also can't enable it when starting a drag for the same reason.
Now, this delay is only present the first time hardware layers are created, so ideally I would want them to be created as soon as the views are added to the layout. I've been pointed to View.buildLayer(), but I'm unsure how to approach this.
What would be the correct way to achieve this?
Are there any methods in my ViewGroup I can override and call buildLayer() on the child views?
Can the hardware layer be invalidated in some way, causing another 70-100ms delay? And how do I handle this?
The delay happens when there's no layer in the cache, you should not see this delay for subsequent calls to setLayerType(NONE)/setLayerType(HARDWARE). You could call buildLayer() from onSizeChanged() to force a layer to be built and then put in the cache (call setLayerType(NONE) to move the layer to the cache.)
Note that the delay you are seeing depends greatly on the device you are running on.
The reason why you shouldn't keep layers enabled is that it doubles the amount of drawing work every time the view update. For instance, if you move a ListView into a layer and then scroll the list, each frame update during the scroll animation will cause: (a) the list to repaint into the layer (b) the layer to be drawn on screen. It's extremely wasteful and may cause performance issues depending on the complexity of your UI.
Say I'd like to make a memory/pairs game. I have currently made a draft that works on a Canvas, and cards are drawn into a grid.
This works for my current basic version, but I'd like show do an animation (when the card is turned, it will flip around and scale to higher size; or when the match is found, the cards would rotate around and then go back.
I can't imagine doing this on Canvas, I'd have to make a lot of timers and do the animation by hand, it seems overly complex for this simple task.
I think I could could subclass View for a control that would display a card, and then react to touch events for that control. It would also make drawing scaling of the images done by Android itself, and, most importantly, I could use Tween Animation for some effects.
My question is - would it be OK to use a View for each card in the game (I could have 5x6 or 4x5 cards), and arrange them in a GridView? Are there some pitfalls with this approach? Or should I continue with completely custom-drawn Canvas?
For such a simple game you should be fine using a collection of Views. As you mention using Views rather than trying to do it manually you get access to a lot of nice Animation functionality for free.
It also makes implement the user interface a lot simpler as you can just add onClickListeners to each view to capture user touches. If you're drawing it all manually to a Canvas then you'd have to interpret the touches yourself and decide which card was touched etc. While this isn't too hard, then I think subclassing View is a better model and will most likely result in cleaner code.
As you are only going to have 30 cards, then I can't imagine you having performance issues either - if you were thinking 100+, then maybe you'd have an issue, but I think you're fine. Also, if I understand your game correctly, the majority of your cards won't be animating most of the time so that's yet another reason not to worry - if you ever run into performance issues with the animations you can easily save off all the unanimated Views onto a Bitmap (Canvas) for the duration of the animation.
I'm new to Android application development and I'm currently experimenting with various UI ideas. In the image below, you can see a vertically scrolling list of horizontally scrolling galleries (and also textviews as you can see). I'm also doing some matrix and camera transformations which I will come to in a minute.
For the background of the list elements, I use green. Blue is the background of the galleries, and red is the background for the images. These are just for my benefit of learning.
The galleries being used are extended classes where I overrode the drawChild method to perform a canvas scale operation in order for the image closest to the center (width) to be larger than the others.
The list view going vertically, I overrode the drawChild method and used the camera rotations from lack of depth dimension in the canvas functionality. The items in the list are scaled down and rotated relative to their position's proximity to the center (height).
I understood that scrolling and clicking would not necessarily follow along with the image transforms, but it appears as though the parent Gallery class's drawing is constrained to the original coordinates as well (see photo below).
I would love to hear any insight any of you have regarding how I can change the coordinates of the galleries in what is rendered via gallery scroll and the touch responsiveness of said gallery.
Images in the gallery are not same dimensions, so don't let that throw you in looking at the image below
Thanks in advance!
Ben
link to image (could not embed)
-- Update:
I was using my test application UI and noticed that when I got the UI to the point of the linked image and then I touched the top portion of the next row in the list, the gallery updated to display the proper representation. So, I added a call to clearFocus() in the drawChild method and that resulted in more accurate drawing. It does seem a tad slower, and since I'm on the Incredible, I'm worried it is a bloated solution.
In any event, I would still appreciate any thoughts you have regarding the best way to have the views display properly and how to translate the touch events in the gallery's new displayed area to its touchable coordinates so that scrolling on the actual images works when the gallery has moved.
Thanks!
As I updated earlier, the issue of the graphics of the gallery not fully refreshing was resolved by calling clearFocus in drawChild method for the ListView extending class.
The problem with registering the touch events turned out to be where I had used an example for the basis of my experimental program which called a pre-translation on the matrix used for painting. Once I removed that call and adjusted the post-translate call to compensate not having the pre-translate call any longer, I was able to scroll through the galleries regardless of their position, size or rotation (around x axis).