Are there any geeks out there interested in new podcasts? What about podcasts about Android development?
Tor Norbye and I are proud to announce a new podcast we've started called Android Developers Backstage. It's a podcast by and for Android programmers, featuring engineers on the Android team at Google talking about features, APIs, and technologies that we think are important for developers to know about. Or which we find interesting. Or which randomly happened to come up on the show.
If your podcast client still has room and you have an extra half-hour (ish) every month (ish), then subscribe and tune in. You can find the podcast on Feedburner. Just click on one of the various links on that page to add it to your podcast client of choice.
The inaugural episode is about Android KitKat, with Tor and I talking about some of the new features in the latest release. In future episodes of the podcast, we'll interview other engineers on the team to deep-dive technologies they've worked on. Android development info, straight from the source.
Graphics geek, performance pusher, animation animal
All content on this blog, unless marked otherwise, is original and is copyright © Chet Haase 2006-2015, all rights reserved.
Wednesday, November 27, 2013
Thursday, October 31, 2013
Android KitKat: Developer Info
We just released Android KitKat and posted lots of information about it:
Developer highlights: http://developer.android.com/about/versions/kitkat.html
Android Developers Blog: http://android-developers.blogspot.com/2013/10/android-44-kitkat-and-updated-developer.html
Videos (an overview one plus lots of others that dive deeper into specific features): https://www.youtube.com/watch?v=sONcojECWXs&list=PLWz5rJ2EKKc-2quE-o0enpILZF3nBZg_K&index=1
I'll specifically call out the video on Transitions, which is something I recorded last week after finally finishing the feature. I hope that the API is another step toward making animations easier and more automatic in Android applications.
Developer highlights: http://developer.android.com/about/versions/kitkat.html
Android Developers Blog: http://android-developers.blogspot.com/2013/10/android-44-kitkat-and-updated-developer.html
Videos (an overview one plus lots of others that dive deeper into specific features): https://www.youtube.com/watch?v=sONcojECWXs&list=PLWz5rJ2EKKc-2quE-o0enpILZF3nBZg_K&index=1
I'll specifically call out the video on Transitions, which is something I recorded last week after finally finishing the feature. I hope that the API is another step toward making animations easier and more automatic in Android applications.
Thursday, September 12, 2013
Lazy Lists
Let's talk about laziness. No, let's not just talk about being lazy - let's do something about it. Let's be lazy.
There's a common pattern that I use in Android programming where I will create objects lazily, especially when these objects will not necessarily or frequently be needed at runtime. This is especially true for code that I write for the Android framework, where we like to be as lean as possible and leave more memory available for the system and the application.
Often, these objects are collections. My personal favorite is
Of course, you can't simply start poking into a lazily-created collection willy-nilly, unless you're a big fan of NullPointerExceptions. So you need to first check whether the thing is null, and then create it as necessary. Similarly, if you're removing an item from the collection, you might want to check if it's now empty and reset the field to
None of this is difficult... but it is tedious. And it tends to bloat the code that you have to read and write and maintain all over the place. And it's exactly the kind of thing that is easy to get wrong because your mind just blurs over the repeated pattern like it's yet another pile of dirty laundry next to the bed.
So I wondered if there was a way I could encapsulate the behavior I wanted to make my laziness easier, simpler, and more readable. And it turns out there was such a way (or else this would be a very short article that would have ended right around... now).
But first, let's look at the problem a bit more, to understand what we're trying to fix.
I have a class called
Then there are add/remove fields for the int/float types I care about:
There are a few things to notice about these methods:
We can call the methods above and produce lists that dynamically change with the items that we add/remove. For example, this code creates the class, adds items to the two lists, and removes those items:
Adding a bit of tracing code gives us this output:
So there's not too much cruft above, but I figure the second time I'm repeating the same code, I should think about refactoring it in a way that avoids the repetition. And it's easy to imagine that there might be several places in real code that wants to add/remove items, or several different types going into several different types of collections. Then it's easy to see the little bits of repeated code above bloating into more than you might want to manage in the long haul.
There are various ways that you could do this, depending on the collection(s) you want to support, the extra logic you'd like (like my requirement for uniqueness in the lists), and stylistic elements about static methods, etc. But here's what I wound up with:
This simple class has two static methods on it to support adding and removing from an arbitrary List object. As needed, it will create a new List (actually, an ArrayList, but that's an implementation detail). It will check for uniqueness in the
There is an important piece here that makes this work - callers must supply their target list as both a parameter to the function and as the recipient of the return value; this is what makes it possible for these utility methods to allocate or null-out the list as appropriate (since they do not have access to the original list, but only have a reference to it).
Given these two static utility methods, we can now write new
Calling these methods looks remarkably similar to what we saw before:
and results in exactly the same output (which shouldn't be a surprise. If the results were different, this approach wouldn't be a utility as much as a bug):
The
If this were public API, I could envision the manager class offering various different kinds of collections and options, or maybe wrapping more of the capabilities of collections classes (like isEmpty() or contains()). But for now, it's a nice little internal class that can help me simplify my code whenever I need to use this lazy-allocation pattern.
All of the interesting code is inline above, but if you want the two source files, you can download them here.
There's a common pattern that I use in Android programming where I will create objects lazily, especially when these objects will not necessarily or frequently be needed at runtime. This is especially true for code that I write for the Android framework, where we like to be as lean as possible and leave more memory available for the system and the application.
Often, these objects are collections. My personal favorite is
ArrayList
(ever since I moved on years ago from the original, but somewhat crusty, Vector
class), although I am also known to use Hashmap
for those key/value pair situations (especially after I got used to ActionScript's paradigm of everything-is-a-hashmap).Of course, you can't simply start poking into a lazily-created collection willy-nilly, unless you're a big fan of NullPointerExceptions. So you need to first check whether the thing is null, and then create it as necessary. Similarly, if you're removing an item from the collection, you might want to check if it's now empty and reset the field to
null
again.None of this is difficult... but it is tedious. And it tends to bloat the code that you have to read and write and maintain all over the place. And it's exactly the kind of thing that is easy to get wrong because your mind just blurs over the repeated pattern like it's yet another pile of dirty laundry next to the bed.
So I wondered if there was a way I could encapsulate the behavior I wanted to make my laziness easier, simpler, and more readable. And it turns out there was such a way (or else this would be a very short article that would have ended right around... now).
But first, let's look at the problem a bit more, to understand what we're trying to fix.
I have a class called
LazyLists
with a couple of List fields and some methods for adding and removing items of various types. First, there are the fields:List<Integer> intList = null; List<Float> floatList = null;
Then there are add/remove fields for the int/float types I care about:
public void addItem(int item) { if (intList == null) { intList = new ArrayList(); } if (!intList.contains(item)) { intList.add(item); } } public void removeItem(int item) { if (intList != null) { intList.remove((Object) item); if (intList.isEmpty()) { intList = null; } } } public void addItem(float item) { if (floatList == null) { floatList = new ArrayList (); } if (!floatList.contains(item)) { floatList.add(item); } } public void removeItem(float item) { if (floatList != null) { floatList.remove(item); if (floatList.isEmpty()) { floatList = null; } } }
There are a few things to notice about these methods:
- There's all of that boilerplate code I mentioned before that lazily creates and nulls out the appropriate list based on the state of the list at the time. This is what we'd like to clean up, since this code is repeated as many times as we have to access these list fields.
- I run a uniqueness check in the
addItem()
methods because it suits me; I only want to add unique items, not the same items over and over. That's kind of a detail that's specific to my situation, but produces more boilerplate that I'd love to get rid of. - There an interesting nuance to the int variation of
removeItem()
. Do you see it? It's the cast toObject
prior to removing the item fromintList
. This is because of the awkward crossover between primitive types (int, float, etc.) and Object types (Integer, Float, etc.) in Java. There are actually tworemove()
methods on List, one that takes anint
and one that takes anInteger
. The one that takes anint
removes the item at that index, whereas theInteger
variant removes that item itself. That's a pretty huge distinction. And maybe it's well-known to you if you've worked with Lists and ints, but I hit it when working on this example, and thought it wasint
eresting enough to call out.
We can call the methods above and produce lists that dynamically change with the items that we add/remove. For example, this code creates the class, adds items to the two lists, and removes those items:
LazyLists lists = new LazyLists(); lists.addItem(0); lists.addItem(1f); lists.removeItem(0); lists.removeItem(1f);
Adding a bit of tracing code gives us this output:
starting lists = null, null populated lists = [0], [1.0] ending lists = null, null
So there's not too much cruft above, but I figure the second time I'm repeating the same code, I should think about refactoring it in a way that avoids the repetition. And it's easy to imagine that there might be several places in real code that wants to add/remove items, or several different types going into several different types of collections. Then it's easy to see the little bits of repeated code above bloating into more than you might want to manage in the long haul.
There are various ways that you could do this, depending on the collection(s) you want to support, the extra logic you'd like (like my requirement for uniqueness in the lists), and stylistic elements about static methods, etc. But here's what I wound up with:
public class LazyListManager { public staticList add(List list, T item) { if (list == null) { list = new ArrayList (); list.add(item); } else if (!list.contains(item)) { list.add(item); } return list; } public static List remove(List list, T item) { if (list != null) { list.remove(item); if (list.isEmpty()) { list = null; } } return list; } }
This simple class has two static methods on it to support adding and removing from an arbitrary List object. As needed, it will create a new List (actually, an ArrayList, but that's an implementation detail). It will check for uniqueness in the
add()
method, check for nullness in the remove()
method, and null out an empty list in remove()
as appropriate.There is an important piece here that makes this work - callers must supply their target list as both a parameter to the function and as the recipient of the return value; this is what makes it possible for these utility methods to allocate or null-out the list as appropriate (since they do not have access to the original list, but only have a reference to it).
Given these two static utility methods, we can now write new
addItem()
and removeItem()
methods that are a significantly better (you can't get less than one line of code, unless I missed that part in my CS education):public void addItemBetter(int item) { intList = LazyListManager.add(intList, item); } public void removeItemBetter(int item) { intList = LazyListManager.remove(intList, item); } public void addItemBetter(float item) { floatList = LazyListManager.add(floatList, item); } public void removeItemBetter(float item) { floatList = LazyListManager.remove(floatList, item); }
Calling these methods looks remarkably similar to what we saw before:
lists.addItemBetter(0); lists.addItemBetter(1f); lists.removeItemBetter(0); lists.removeItemBetter(1f);
and results in exactly the same output (which shouldn't be a surprise. If the results were different, this approach wouldn't be a utility as much as a bug):
starting lists = null, null populated lists = [0], [1.0] ending lists = null, null populated lists = [0], [1.0] ending lists = null, null
The
LazyListManager
class has taken out all of the tedious boilerplate related to null checks, uniqueness, allocation, and nullification, and has left us with just one line of code to write whenever we want to add or remove items to/from one of our lists. That's just about the right amount of code for me to write without making a typo or a copy/paste error along the way.If this were public API, I could envision the manager class offering various different kinds of collections and options, or maybe wrapping more of the capabilities of collections classes (like isEmpty() or contains()). But for now, it's a nice little internal class that can help me simplify my code whenever I need to use this lazy-allocation pattern.
All of the interesting code is inline above, but if you want the two source files, you can download them here.
Friday, August 9, 2013
DevBytes: Cartoon Animation Techniques
This time, we wrap up the series on cartoon animation techniques with a demo that shows a few of the techniques in the context of a larger application. Because it's nice to know how to write the code, but you might also be wondering why you might want to.
For some real-world context, you could also check out games such as Candy Crush Saga (a horribly addictive game I've gotten sucked into that's less like casual gaming and more like casual crack). It uses a veritable plethora of cartoon animation techniques to keep the player engaged with the game and disengaged from their life.
This and other cartoon animation techniques were discussed in the talk A Moving Experience at Google I/O 2013
Code: http://developer.android.com/shareables/devbytes/ToonGame.zip
YouTube: https://www.youtube.com/watch?v=8sG3bAPOhyw&list=PLWz5rJ2EKKc_XOgcRukSoKKjewFJZrKV0
For some real-world context, you could also check out games such as Candy Crush Saga (a horribly addictive game I've gotten sucked into that's less like casual gaming and more like casual crack). It uses a veritable plethora of cartoon animation techniques to keep the player engaged with the game and disengaged from their life.
This and other cartoon animation techniques were discussed in the talk A Moving Experience at Google I/O 2013
Code: http://developer.android.com/shareables/devbytes/ToonGame.zip
YouTube: https://www.youtube.com/watch?v=8sG3bAPOhyw&list=PLWz5rJ2EKKc_XOgcRukSoKKjewFJZrKV0
Friday, August 2, 2013
DevBytes: Squash & Stretch
Cartoon animation uses a technique called "squash & stretch" for achieving different effects of objects interacting with their environment.
This episode shows how we can use similar techniques to get more organic and lively animations in user interfaces.
This and other cartoon animation techniques were discussed in the talk A Moving Experience at Google I/O 2013.
Code: http://developer.android.com/shareables/devbytes/SquashAndStretch.zip
YouTube: https://www.youtube.com/watch?v=wJL1oW6DlCc
This episode shows how we can use similar techniques to get more organic and lively animations in user interfaces.
This and other cartoon animation techniques were discussed in the talk A Moving Experience at Google I/O 2013.
Code: http://developer.android.com/shareables/devbytes/SquashAndStretch.zip
YouTube: https://www.youtube.com/watch?v=wJL1oW6DlCc
Friday, July 26, 2013
DevBytes: Anticipation & Overshoot, Part 2
Like my previous DevBytes episode, Anticipation and Overshoot, Part I," this episode covers cartoon animation techniques for making UI elements more engaging and playful. The code in this episode shows how to change and animate how a button is drawn to make it seem more alive and organic.
This and other cartoon animation techniques were discussed in the talk A Moving Experience at Google I/O 2013.
Code: http://developer.android.com/shareables/devbytes/Anticipation.zip
YouTube: DevBytes: Anticipation and Overshoot - Part 2
This and other cartoon animation techniques were discussed in the talk A Moving Experience at Google I/O 2013.
Code: http://developer.android.com/shareables/devbytes/Anticipation.zip
YouTube: DevBytes: Anticipation and Overshoot - Part 2
Thursday, July 25, 2013
New in Android 4.3: ViewOverlay
Since we just released Android 4.3 yesterday, I thought I'd wax poetic about one of the features I worked on in the release: Overlays.
There are many ways to get custom graphics (drawables) to appear in a view. You can set a background drawable if that's what you want, or you can use an ImageView, or you can create a custom View subclass and override onDraw(). Or if you want to draw them over the children in a layout, you can override the layout and override dispatchDraw() to draw them after all of the children (after a call to super.dispatchDraw()). But sometimes you just want something simpler: ViewOverlay.
Here's how it works:
You call View.getOverlay(), which returns a ViewOverlay object. Then you call add(Drawable) on that overlay object... and that's it. You can also call remove(Drawable) to get rid of the drawable or clear() to get rid of everything in the overlay, but that's the entire API. The only other detail is that you need to set the bounds on your drawables (as you would if you were drawing them manually in onDraw()); the overlay doesn't do any positioning or sizing, it simply draws everything you tell it to, in the order in which the objects are added.
Oh, and one other thing: you can also add View objects to an overlay if you get that overlay from a ViewGroup. That is, ViewGroup overrides getOverlay() to return a ViewGroupOverlay, which is a subclass of ViewOverlay that also deals with views in addition to drawables. Once again, the API is simple: there's an add(View) method and a remove(View) method. And once again, you are responsible for positioning/sizing the views where you want them in the overlay; the overlay does not do any layout.
Essentially, the overlay is a container for drawables (and sometimes views) that is the exact size of its host view. It doesn't do layout; it just draws the stuff its told to, after it's drawn everything else in its host view (including any children of that host view, if the view is a ViewGroup).
Important caveat, especially with respect to ViewGroupOverlay: The overlay is intended for temporary display of views, not for any long-term or functional use for views. In particular, the views there are not laid out by the container (as noted above) and do not participate in focus or input events. Overlays were created to be a visual-only mechanism, for things like transient animations. Think about things like fading out a view. This can be tricky in some situations where removing it immediately removes it from the view hierarchy and makes it tough to have it drawn while it's fading out. Now you can pop it into the overlay of its parent while it's going away.
Here's another interesting thing to ponder: you can add drawables/graphics anywhere in the view hierarchy that makes sense for your situation. So, for example, if you wanted to fade out a view or some drawable while sliding it off the screen, or up-scaling it, outside of its parent container, this might normally be a problem because parent containers like to clip their children to their bounds by default. Now you can add the object into an overlay anywhere up the tree, to give you the flexibility to move/resize it as you see fit without worrying about the clipping constraints of that original parent.
Anyway, I'm sure you can find interesting things to do with overlays. So go ahead!
Android devs
Come out to play:
Use the new
ViewOverlay.
Here's how it works:
You call View.getOverlay(), which returns a ViewOverlay object. Then you call add(Drawable) on that overlay object... and that's it. You can also call remove(Drawable) to get rid of the drawable or clear() to get rid of everything in the overlay, but that's the entire API. The only other detail is that you need to set the bounds on your drawables (as you would if you were drawing them manually in onDraw()); the overlay doesn't do any positioning or sizing, it simply draws everything you tell it to, in the order in which the objects are added.
Oh, and one other thing: you can also add View objects to an overlay if you get that overlay from a ViewGroup. That is, ViewGroup overrides getOverlay() to return a ViewGroupOverlay, which is a subclass of ViewOverlay that also deals with views in addition to drawables. Once again, the API is simple: there's an add(View) method and a remove(View) method. And once again, you are responsible for positioning/sizing the views where you want them in the overlay; the overlay does not do any layout.
Essentially, the overlay is a container for drawables (and sometimes views) that is the exact size of its host view. It doesn't do layout; it just draws the stuff its told to, after it's drawn everything else in its host view (including any children of that host view, if the view is a ViewGroup).
Important caveat, especially with respect to ViewGroupOverlay: The overlay is intended for temporary display of views, not for any long-term or functional use for views. In particular, the views there are not laid out by the container (as noted above) and do not participate in focus or input events. Overlays were created to be a visual-only mechanism, for things like transient animations. Think about things like fading out a view. This can be tricky in some situations where removing it immediately removes it from the view hierarchy and makes it tough to have it drawn while it's fading out. Now you can pop it into the overlay of its parent while it's going away.
Here's another interesting thing to ponder: you can add drawables/graphics anywhere in the view hierarchy that makes sense for your situation. So, for example, if you wanted to fade out a view or some drawable while sliding it off the screen, or up-scaling it, outside of its parent container, this might normally be a problem because parent containers like to clip their children to their bounds by default. Now you can add the object into an overlay anywhere up the tree, to give you the flexibility to move/resize it as you see fit without worrying about the clipping constraints of that original parent.
Anyway, I'm sure you can find interesting things to do with overlays. So go ahead!
Subscribe to:
Posts (Atom)