Wednesday, December 14, 2011

Video: SF Android User Group Talks 11/11

Last month, Romain and I once again braved Bay Area rush hour traffic and gave a couple of talks at the SF Android user group. Those talks were recorded and are now posted online:

An Introduction to Ice Cream Sandwich (Android 4.0)
This talk overviews some of the user and developer features of the new Android 4.0 release, through slides and demos. We also got side-swiped by a massive Q&A phase in the middle; always interesting to see what's on peoples's minds (and maybe even answer those questions sometimes).

Sticky GUIs
This talk discusses some principles, approaches, and techniques in graphics, animation, layouts, and performance that may help you create better and more usable UI applications.

(The ICS recording has interesting audio. It reminds me of early efforts at "stereo" with the Chet instrument coming out of your left speaker and the Romain instrument coming out of your right speaker. But the recordings are very good otherwise. And maybe it's better this way - you can just mute one of the speakers and mute the speaker you're tired of).

Tuesday, November 22, 2011

#DevoxxBlog: Of Slides and Such

I spent last week at Devoxx, giving several talks with Romain Guy about Android (graphics, GUIs, performance, the latest developer features ... the usual). Now that I've recovered from a total system collapse over the weekend (apparently the body does insist on getting a little sleep now and then), I thought I'd post some thoughts and also the slides from our presentations.

Thoughts

Devoxx is my favorite developer conference. It is a perfect mix of highly technical (focused on developers, not business/marketing/PR), inexpensive (at 350-700 Euros, it's quite a deal for 2-5 days of full technical content of this caliber, even at the current exchange rate of 1 Euro == $97,000.02), and personal (it's a relatively small, single venue, so you're all together there in the talks, in the lobby, in the hallways, and on the show floor). And it's in an interesting venue (Antwerp, while not balmy in November, is a far more interesting location to return to than, say, San Jose). Oh, and the beer is quite nice.

The conference is well run, the talks are professionally recorded and viewable on the excellent parleys.com website, and the beer is tasty. Parleys, and its free subscription for conference attendees, is particularly crucial since the comfortable theater seating guarantees that you'll have to catch up on at least some of the talks later.

Content

Romain and I gave several talks this year, not all of which have accompanying slides:

University: Android Awesomeness
This vaguely-titled 3-hour talk on Monday was in two parts. In the first half, Romain and I did a very quick introduction to the Android 4.0 release, then Philip Milne (another engineer on the Android framework team) followed up with a deep-dive into the GridLayout class that is new in the 4.0 release. The second half was more interactive, as we showed how we use the tools that ship with the SDK to debug performance, memory, and UI issues.
You can download the slides for this talk here: Part 1 and Part 2.

Lab: Just Desserts: Developing with the Latest Features from Honeycomb and Ice Cream Sandwich
This was a 3-hour lab on Tuesday morning in which we showed how to use some of the new features like fragments, TextureView, layers, and animations. No slides for this one; you had to be there. (I may post code projects later once I whip the code into presentable shape).

Session: Graphics Goodies
Wednesday's talk was an updated version of the Android Accelerated Rendering talk we did at Google IO.
Here are the slides.

Session: Sticky GUIs
This presentation on Thursday was a collection of techniques and principles for creating GUI applications that will make your users stick: graphics, performance, animations, GUIs; they're all important.
Here are the slides.

Android Awesomeness, Graphics Goodies, and Sticky GUIs were all recorded and will be available soon on the parleys.com website. You may get more out of the full presentations than from just the slides. In fact, I hope you do, because otherwise I don't know why we traveled that far to present them.

Saturday, November 5, 2011

Devoxx: Then and Now

I'm starting to prepare presentations for the ~8 hours of talks that Romain and I are giving at Devoxx in a couple of weeks. "Preparing" generally entails mostly worrying, followed by a mad rush of writing slides and code at night, on the long flight, after beers, between talks, and sometimes during the talks. It's a busy time of year.

I realized that the organizers of Devoxx had recently released all of the recorded talks from last year into the wild (read: they're free on parleys.com), so it seemed worth linking to them in case anyone wanted to see what we had to say last time around.

I'll give a plug for the conference and the Parleys site here. If there were an ad banner, it'd go here. Not because I'm paid (I would make a poor ad salesman, apparently), but because I think that both the conference and the parleys site rock. The organizers do a great job of putting it all together, and the recordings and presentation of the talks on parleys.com is the best I've seen by far of any conferences I've spoken at.

Yes, that young man on the pedestal is
throwing a hand. It's an Antwerp thing.
Parleys is a subscription site; after the annual conference, you can join for the year (for a fee of 79 Euros) to watch all talks given at the conference. During that year, the talks are made freely available, one by one, then at the end they are all free. That year has passed, so the 2010 talks are all available now for free. If you enjoy them, consider joining parleys next time around to see them earlier. Or better yet, join us in balmy Antwerp, where the beer is good and so are the fries.

Dive into Android, Part 1
Romain talks about layout. This talk includes live-coding a custom layout, which is a good lesson in how to do it yourself (although you probably don't need to do it on stage in front of the cameras to make it work the way you want).

Dive into Android, Part 2
I talk about custom graphics. This is kind of a Filthy Rich Client talk, but more focused on the core principles and approaches of doing custom graphics in Android applications. nothing over-the-top filthy, just good stuff to know about Android GUI development.

Android Graphics and Animations
We cover lots of architectural details about the Android platform, including the view hierarchy, classes used in custom graphics, and pre-3.0 animations (remember: this talk was given before Android 3.0 (Honeycomb) was released).

Android UI Development: Tips, Tricks, & Techniques
This talk consists of a smattering of tips that will help you write efficient Android applications. We discuss the various tools that you should use, techniques for avoiding unnecessary garbage creation, and various performance tips.

Flex 4 FunThis is my swan song for the platform that I worked on prior to Android, and for my Flex 4 Fun book that was published last year. I cover various things from the book, including graphics objects, filters, states and transitions, component skinning, and (of course) animation effects (the area I worked on for Flex 4). Lots of demos and code.

Tuesday, November 1, 2011

Android 4.0 Graphics and Animation

Romain and I wrote this article for the Android developer blog about graphics and animation features (what else?) in the latest Android release.

Enjoy...

http://android-developers.blogspot.com/2011/11/android-40-graphics-and-animations.html

Friday, September 16, 2011

Old Views Don't Die; They Just Fade Away

One of the app developers here on Android asked me about the best way to animate adding and removing items from a UI. Specifically, he wanted to fade items in and out as they became visible/invisible.

So I wrote up a sample activity that used ViewPropertyAnimator, showing how to set the visibility at the right time (making it visible before fading it in, listening for the onAnimationEnd() to set it invisible after fading it out). Pretty straightforward, but if you haven't played around a lot with the new animation classes yet (WHY HAVEN'T YOU?!?!), it's probably not obvious:

To make it invisible:
invisibleButton.animate().alpha(0f).setListener(new AnimatorListenerAdapter() {
                    public void onAnimationEnd(Animator animation) {
                        invisibleButton.setVisibility(View.INVISIBLE);
                        invisibleButton.setAlpha(1f);
                        invisibleButton.animate().setListener(null);
                    }
                });
To make it visible again:
invisibleButton.setAlpha(0);
                    invisibleButton.setVisibility(View.VISIBLE);
                    invisibleButton.animate().alpha(1);

I sent the sample application along to the developer.

Then I thought I'd add to that sample and show how to also add/remove views, or set them to View.GONE as well as View.INVISIBLE.

I sent that updated sample to the developer as well.

Then I thought I might as well show how you'd do the same thing with ObjectAnimator. It's a little more code than ViewPropertyAnimator, but still pretty straightforward. For example, fading the object out and making it invisible looks like this:
                ObjectAnimator anim = ObjectAnimator.ofFloat(invisibleButton1, "alpha",0);
                anim.addListener(new AnimatorListenerAdapter() {
                    public void onAnimationEnd(Animator animation) {
                        invisibleButton1.setAlpha(1);
                        invisibleButton1.setVisibility(View.INVISIBLE);
                    }
                });
                anim.start();

I sent this further updated sample to the developer.

Then I thought I'd poke at a utility class that's been on my mind for a while. We have all of these new animation capabilities as of the Honeycomb release, but I'd still like it to be simpler to run these kinds of animations, especially ones that involve several actions like this: fade this view out, then remove it. So I wrote up a Fade class that has utility methods in it for fading/adding/removing/etc. I enhanced the sample to use the new Fade utilities. Now making a view invisible is just one step:
                fade.hide(invisibleButton2, View.INVISIBLE);
Similarly, making that view visible again is a single call:
                fade.show(invisibleButton2);

I sent this latest version of the sample to the developer. He was getting pretty tired of hearing from me by this time.

Then I tweaked the Fade class to have a duration property.

I was going to send this final (ha!) update to the developer, but I didn't want him to call security on me. I think he got what he needed the first time around. So rather than continue to bury him in yet more ways to accomplish this simple task, I thought I'd publish it here.

Check out the sample code for FaderActivity, which shows all of these things: ViewPropertyAnimator, ObjectAnimator, and this new Fade utility class. I hope that something like the Fade class and other higher-level animation classes will make it into the SDK eventually, but in the meantime, Fade should simplify fading tasks.

There are a couple of things to note about fading animations. One thing is that there is an abrupt 'pop' when an item is removed from or added to a layout that is affected by that change. For example, the LinearLayout used in the example expands or contracts when the first button is removed or added or when the last button is set to VISIBLE or GONE (although you can't see that change since it's the last item in that layout). There's nothing to be done about this problem right now, although you might play with the LayoutTransition class available in 3.0, which animates the layout changes as well.

It's also worth noting that the Fade class is great at fading things out from their current alpha and then back to an alpha value of 1 (fully opaque). It does not compensate for in-between alpha values that your views might want to persist between fades. That logic could be added, but there's some tedious logic around knowing when an in-between value is coming from the view itself vs. some other fade animation that happens to be running when you start the new one (for example, you fade an item out and then, halfway through, you fade it back in). The Fade class is great for the common case where views are typically just opaque (alpha == 1). But it seemed worth mentioning.

You can grab a zipped version of the Eclipse project with the source for the example activity and the utility Fade class here.

Enjoy.

Wednesday, August 24, 2011

The Mysterious Behavior of fillBefore, fillAfter, and fillEnabled

A bug was filed on android.com recently that had me poring through the code and docs to understand three boolean flags in the old Animation class: fillBefore, fillAfter, and fillEnabled. On the surface, these properties don't seem that difficult to understand; they control how animations behave before and after they run. But between some complicated interactions of the properties and some, er, inaccuracies in the reference docs, it turned out to be somewhat tricky to understand how they work and how they're supposed to work. Once I got through that exercise (including fixing the docs - look for those fixes in a future release), I thought it might be helpful to explain how these flags really work.

First, let's cover the behavior of fillBefore and fillAfter. We'll get to fillEnabled and it's, um, special behavior after that.

Before and After

fillBefore and fillAfter are pretty simple, conceptually; they define how an animation behaves before and after it runs. fillBefore controls whether the initial value of the animation is applied before its start time and fillAfter controls whether the animation's ending value persists after it ends. There are a couple of important nuances to understand, however.

  • start time: The starting time of an animation, for the purposes of fillBefore, is not the time when you call startAnimation() on a View. Rather, it's the time that the animation will actually start running. These two times are the same if there is no startOffset set on the animation, but if you want to delay your animation, you might set a startOffset value to achieve that delay. fillBefore controls whether the animation will use the initial value of the animation during that startOffset phase.
  • AnimationSet: If you want to control the fill behavior of an animation that is inside an AnimationSet, it is certainly possible to do this. But if you want to control what happens outside the runtime of that AnimationSet, then you need to set the fill behavior on the set itself. For example, the fillAfter flag controls whether a ScaleAnimation's end value is used after it ends. But if the animation you set on your View is actually an AnimationSet containing that inner ScaleAnimation, then you need to set fillAfter on the AnimationSet if you want the value to persist after the AnimationSet ends. You can think of the fill behavior flags as having scope, which is either global (when not contained in an AnimationSet) or local to the AnimationSet in which their contained. Or you can just play with them enough to get the hang of it, like I did. It's also worth noting, as stated in the docs (correctly this time) that if you set the value of fillBefore or fillAfter these values will override those in the child animations of the set.

The default values for these flags are true for fillBefore and false for fillAfter. So by default, animations will set their initial value immediately when the animation starts (regardless of startOffset), but will not persist those values after they end.

So that's all there is to those flags: you set or unset them according to whether you want the animation values to be used outside of when the animation is actually running. Well, sort of...

The Enabler

Here's where the other flag, fillEnabled, comes in. This flag controls when the other flags are actually taken into account. Or that's what some of the docs would have you believe. In actual fact, this flag controls only the behavior of fillBefore, and essentially leaves fillAfter to its own devices.

Here's how the value of fillEnabled works:

  • false: If fillEnabledis false (which it is by default), then the value of fillBefore will be ignored. That's right, you can set or unset it all you want, but it will ignore your wishes and will essentially assume that fillBefore is true.
  • true: When fillEnabled is true, the value of fillBefore will be taken into account to determine whether to apply the animation before it begins. The value of fillAfter, as I said earlier, will be used as-is, regardless of the value of fillEnabled.

All of this means that the only way to get an animation to not persist its starting value before it actually starts running is to set both fillEnabled to true and fillBefore to false. Any other combination will result in the animation being applied before its starting time. Meanwhile, the value of fillAfter is applied directly, regardless of the value of fillEnabled. I believe it is this asymmetric behavior (coupled with an unfortunately generically named "fillEnabled" property and some, well, bugs in the docs) that made these three variables particularly difficult for some people to understand. Some people like me.

At this point, you might be asking yourself why these variables were created and defined in this way. All I can say is, welcome to the wonderful world of API development, where behavior needs to evolve while compatibility is preserved. In any case, I hope this explanation helps those who needed it.

p.s. For those starting to use the new animation system introduced in Android 3.0, you can forget about all of this; there is no fill behavior (before, after, or enabled) for Animator-based animations.

Thursday, August 4, 2011

DroidFlakes: An Android Animation Demo

Here's a simple app that I wrote recently to see how background processing affects frame rate. There's nothing too complicated going on in the app, but it seemed worth publishing to show how to do various things in Android, such as:

  • Using a single ValueAnimator (3.0+ API) to animate several objects independently
  • Manipulating the transform of Canvas to move/rotate objects
  • Using the GPU to provide faster rendering (3.0+ capability)
  • Tracking the current frames per second performance
Here's a video of the running application, captured using HDMI on a 3.1 tablet. You can see how the More, Less, and GPU controls affect what's going on in the app. Note that it starts out with no GPU acceleration and bogs down when we have lots of flakes on the screen. Then see how the frame rate improves once the GPU box is checked. The app is accelerated by default; non-GPU rendering is performed by setting a software layer on the view, which forces rendering to happen in software to a bitmap, which is then copied into the view.

Here's the code (a zipped Eclipse project for the app). You should be able to build/run it for any 3.0+ target device.

Note: this is not the Renderscript app that I showed in a recent user group talk. That other app is based on this one, but uses Renderscript to animate and draw the droidflakes. This version just uses the standard Canvas API to draw bitmaps. I'll post the Renderscript version soon.