Showing posts with label demo. Show all posts
Showing posts with label demo. Show all posts

Friday, June 27, 2014

Google I/O 2014: Rehash

All of the videos have been posted from the various sessions I was in this year. Here they are, along with links to the slides.

What's new in Android

A presentation with +Dan Sandler that provides a quick overview of some of the larger features and new APIs in the L Developer Preview release and other new bits in the recent Androidosphere. There's also a really good deep-dive into Notifications, since Dan's the non-local expert on the subject.



Slides (PDF)


Material science

This session, presented with +Adam Powell, provides an overview of the engineering side of the Material design system. Many of the other sessions at Google I/O this year discussed the design side; this presentation covers the technical details of the APIs and the capabilities exposed by the framework for Android developers.



Slides (PDF)


Material witness

I was happy to be joined once again by former Android developer and UI Toolkit team lead +Romain Guy for this talk on some of the new Material design elements in the L Developer Preview release. The idea behind this talk was to go a bit deeper into using and explaining the new APIs, as well as explaining how some of the features, like realtime soft shadows, work.



For slides as well as demo code, check out Romain's blog at curious-creature.org.


Android fireside chat

This session, organized and moderated by +Reto Meier, I found to be more interesting than other such panels I've seen. Often, these things tend to have a lot of awkward silences as the panelists try to figure out the most interesting way of saying "No comment" since there's a general policy on Android of not talking about future development plans. This time, there was a lot of discussion around how and why some parts of the system work, which I enjoyed as an audience member that just happened to be sitting somewhat closer to the panel.

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 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 to Object prior to removing the item from intList. This is because of the awkward crossover between primitive types (int, float, etc.) and Object types (Integer, Float, etc.) in Java. There are actually two remove() methods on List, one that takes an int and one that takes an Integer. The one that takes an int removes the item at that index, whereas the Integer 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 was interesting enough to call out.
Anyway, moving on.

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 static  List 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 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



Or, in illustrated form:



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

Friday, July 19, 2013

DevBytes: Anticipation and Overshoot, Part 1

Some principles of cartoon animation can be used to provide more engaging and more interactive experiences in applications.

This episode demonstrates principles of anticipation and overshoot with a simple button click, showing how to animate changes in the button's appearance to make it interact more playfully with the user.

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/LiveButton.zip

YouTube: https://www.youtube.com/watch?v=uQ7PTe7QMQM


Friday, July 12, 2013

DevBytes: Curved Motion

This is a demo that +Romain Guy and I showed in our A Moving Experience talk at Google I/O this year, showing how to use the existing TypeEvaluator and Animator APIs to get curved motion for your animations.

In the real world, things don't move in straight lines. Moving items around on the screen should feel as natural as possible; sometimes curved motion can help.

This episode shows how to use the existing animation APIs to get easy curved motion for your UIs.

The helper classes come from an article I posted on my blog last year:
http://graphics-geek.blogspot.com/2012/01/curved-motion-in-android.html

YouTube: https://www.youtube.com/watch?v=JVGg4zPRHNE

Code: http://developer.android.com/shareables/devbytes/CurvedMotion.zip

Friday, June 28, 2013

DevBytes: Animating Multiple Properties in Parallel

Suppose you want to animate multiple properties in parallel on some target object. How would you do it? ValueAnimator? Multiple ObjectAnimators?

This episode covers different ways of animating multiple properties, and specifically covers the use of the lesser-known PropertyValuesHolder class.

YouTube: https://www.youtube.com/watch?v=WvCZcy3WGP4

Code: http://developer.android.com/shareables/devbytes/MultiPropertyAnimations.zip

Friday, June 21, 2013

DevBytes: Animating ListView Deletion: Now on Gingerbread!

In this episode, I tried to anticipate the question I knew would come up on my previous show about animating ListView deletion: "But how would I do this on Gingerbread?"

Here's how.

YouTube: https://www.youtube.com/watch?v=PeuVuoa13S8&list=PLWz5rJ2EKKc_XOgcRukSoKKjewFJZrKV0&index=1

Code: http://developer.android.com/shareables/devbytes/ListViewItemAnimations.zip

Friday, June 7, 2013

DevBytes: Custom Activity Animations

It's Friday: time for another DevBytes.

It's been a while, but they're back. At least until the queue runs out again and I write another glut of demos to talk about.

This episode, and most of the upcoming ones (teaser alert!) are around demos/code that we showed in A Moving Experience, the animation talk that +Romain Guy and I gave at Google I/O 2013.

Custom Activity Animations:
Window animations provide an easy way to animate transitions between activities. The animations can be customized to some extent, but there's only so much interaction between the launching and launched activities that you can take advantage of with the standard window animations.
This episode covers a different technique for fully customizable animations.

Video: http://www.youtube.com/watch?v=CPxkoe2MraA

Code: http://developer.android.com/shareables/devbytes/ActivityAnimations.zip

Friday, March 22, 2013

DevBytes: Layout Transitions

The LayoutTransition class (added in Android 3.0) enables easy fade/move/resize animations when items are added to or removed from a ViewGroup, usually with just one line of code. This video shows how this works and also shows the new ability added in JellyBean (Android 4.1) to animate other changes to the layout as well, not limited to items being added or removed.

YouTube:
https://www.youtube.com/watch?v=55wLsaWpQ4g

Code:
http://developer.android.com/shareables/devbytes/LayoutTransChanging.zip

Friday, March 15, 2013

DevBytes: PictureViewer

PictureViewer: How to use ViewPropertyAnimator to get a cross-fade effect as new bitmaps get installed in an ImageView.

TransitionDrawable is a handy and easy facility for cross-fading between two drawables. But if you want to cross-fade between an arbitrary set of images, you might want something more general-purpose. Here's one approach.

YouTube: https://www.youtube.com/watch?v=9XbKMUtVnJA

Code: http://developer.android.com/shareables/devbytes/PictureViewer.zip

Friday, March 8, 2013

DevBytes: Request During Layout

Horrible things can result from calling requestLayout() during a layout pass. DON'T DO THIS.

The demo that I wrote to show why this is bad seems very contrived, but I have since run across application code that did nearly the exact same thing, explicitly calling requestLayout() during onLayout(). Ugh. Typically, the cases where this problem occurs are a tad more subtle than that.

YouTube: https://www.youtube.com/watch?v=HbAeTGoKG6k

Code: http://developer.android.com/shareables/devbytes/RequestDuringLayout.zip

Thursday, January 31, 2013

DevBytes: BitmapAllocation

This example shows how to speed up bitmap loading and reduce garbage collection by reusing existing bitmaps.

Note that the reused bitmap must be mutable and of the same size and configuration as the bitmap you load into it. Not sure if this is clear from the video, although it is documented in the API.

Code: http://developer.android.com/shareables/devbytes/BitmapAllocation.zip

Video: http://www.youtube.com/watch?v=rsQet4nBVi8

DevBytes: BitmapScaling

This example shows how the use of BitmapOptions affects the resulting size of a loaded bitmap. Sub-sampling can speed up load times and reduce the need for large bitmaps in memory if your target bitmap size is much smaller, although it's good to understand that you can't get specific Bitmap sizes, but rather power-of-two reductions in sizes.

Code: http://developer.android.com/shareables/devbytes/BitmapScaling.zip

Video: http://www.youtube.com/watch?v=12cB7gnL6po

Wednesday, January 16, 2013

DevBytes: Short, Focused Android Tutorials

The Android team has just rolled out the first four shows in a new series called DevBytes, which is intended to be very short, focused tutorials on specific developer topics. A quick explanation, maybe a demo, and a few lines of code to walk through and it's done. Taking a break from work? Want to learn something new? Or just wonder how a specific piece of technology works on the platform? Tune into one of the DevBytes episodes to get a quick deep dive into that exact topic (well, assuming we've done a show on that topic. Maybe we could interest you in one of the shows that we've actually filmed yet instead?)

The first few of these feature ... me! (Surprise, surprise!) I'll be doing many of these tutorials over time, especially in the areas of animation, graphics, and UI development, starting with this first set:


ViewAnimations:
This show covers the basics of creating and running pre-3.0 Animations on View objects.

PropertyAnimations:
This show parallels the ViewAnimations demo, but uses the new Animator classes introduced in Android 3.0.

WindowAnimations:
Ever want to use a custom window animation to transition between sub activities? Watch this show.

CrossFading:
TransitionDrawable can be used for very simple cross-fade effects between two different Drawable objects.

There will be other shows coming online in the future as well; we're just starting with some of the ones that I did. I wouldn't mind if everything were about animation, but that's just me...

There are code links in the video descriptions if you want to see the code I cover in the videos. I'll also be posting individual blogs with the video and code links to make this easier, I just wanted to get this introduction/overview out there to get it rolling.

These are just a start: we have more videos on the way in the coming weeks. So tune in and geek out.

Wednesday, January 4, 2012

Curved Motion in Android

The animation support added in Android 3.0 and enhanced since then is useful, allowing a flexible system of property animation to animate literally anything you want. Like a store going out of business: if it ain't nailed down, it's up for grabs.

But that doesn't mean we're done yet; there are many things that we'd like to do to keep improving the animation system and making Android animations easier to write and more powerful. One of those things is curved motion.

Right now, if you animate something between a start and end point, it will move in a straight line between those values. For example, a translation animation, where the object moves from one (x, y) location to another, will move in a straight line beween those points. You can (and should) use non-linear timing for these animations, and the animation framework uses ease-in/ease-out timing by default. But the actual spacial movement is linear; there is no way for you to specify a curved path for an object to take between the end values of an animation.

Even if you use a multi-point keyframe animation, where you specify several intermediate points for the animation to pass through along the way, you are still going to move linearly between each of those points.

One goal with animations is to make them feel as natural as possible. And just as motion in the real world (you know, the one we have to use as we move between the machines of our lives) is not linear, animations in our GUIs should not be limited to linear. For example, f a view moves from corner of the screen to the opposite corner, wouldn't it be nice to have the option to give it a little curve in and out at both ends, instead of being locked into a straight-line movement?

We'd like to add this kind of capability to the animation system in a future release; it needs to be easy to create such animations, we just have to provide the APIs and functionality to let you do it.

As I was looking into the problem, I created some prototype code using the existing animation APIs and realized that there's nothing stopping you from having this capability already. The flexibility of the Animator APIs allow you to do exactly the kinds of operations you need to get curved motion. You just need a little more code to do it.

I thought it would help to post some of my prototype code to show you how. In particular, I thought this sample was interesting because it shows:
  • How to move things along curves and complex paths
  • How to use the Animator APIs to do more than what the base library supports. In particular, how to use TypeEvaluator to animate custom types.

Some notes and caveats before we begin:
  • This is a prototype only, and does not necessarily represent the way it would appear in any final API. It's just a sample program, and a pretty simple one at that.
  • Simply computing the location based on the fraction time elapsed in a curve interval is probably not the motion you want. It will give the mathematically correct motion along that path, but the time spent traveling along any particular length of that curve is dependent on the structure of the curve. Basically, you'll end up with slower and faster portions of the curve. This problem is admirably described on this blog. A more complete solution flattens the curve and ensures uniform speed. But again, it's just a simple demo, so I'll leave correct path-time-distance navigation as an exercise for the reader (and for the writer, since this would be a part of any future implementation in the SDK).
  • The timing of the animation along a multiple-point path such as the one in the demo app is not as flexible as I'd like it to be. Basically, you end up with something that gives equal time in the overall animation to each individual interval. In addition, any "move" operations in the middle of the path cause the animation to wait at that location for that interval's equal slice of the duration. It should be possible, in a more complete implementation, to define the time associated with any particular interval.
  • This description assumes a foreknowledge of Bézier curves; if you have no idea what I'm talking about, you might want to go look them up (such as on the blog linked above or various other places on the web, such as Wikipedia). Or you can just read along, refer to the mathematically imprecise sketch to the right, and hopefully not get too lost.
  • The code as written requires Android 4.0 to build. Actually, it's mostly compatible back to 3.0, but the PathEvaluator class uses a generic specification for TypeEvaluator that was introduced in 4.0 (not necessary, just convenient when I wrote the code).

On with the code.

The activity code is in PathAnimationActivity.onCreate(). First, we set up the path itself:
AnimatorPath path = new AnimatorPath();
    path.moveTo(0, 0);
    path.lineTo(0, 300);
    path.curveTo(100, 0, 300, 900, 400, 500);
Here, we are constructing an AnimatorPath (which is part of the demo project that we'll see below) and supplying it with operations that will become points in the path, along with the operations to navigate the intervals up to those points. The first operation defines where the path starts, (0, 0). Then we move in a straight line to (0, 300). Finally, we move along a curve (a cubic Bézier curve, to be precise) to the point (400, 500), using control points (100, 0) and (300, 900) along the way.

Next, we set up an ObjectAnimator to animate this path:
    final ObjectAnimator anim = ObjectAnimator.ofObject(this, "buttonLoc", 
            new PathEvaluator(), path.getPoints().toArray());
This animator uses a new PathEvaluator object (introduced below). It also queries the AnimatorPath object to get an array of PathPoint (covered below) objects; these will become the points in the animation that define the intervals that we animate between. The animator will send the animated values to the this object, which is the activity instance itself. We implement the setter below to receive those values and pass them along to the actual Button object that we want to move on the screen:
    public void setButtonLoc(PathPoint newLoc) {
        mButton.setTranslationX(newLoc.mX);
        mButton.setTranslationY(newLoc.mY);
    }

The AnimatorPath class referred to above stores information about the overall path. Its API consists of everything seen above:
public void moveTo(float x, float y);
    public void lineTo(float x, float y);
    public void curveTo(float c0X, float c0Y, float c1X, float c1Y, float x, float y);
    public Collection getPoints();

Internally, AnimatorPath uses PathPoint to store the information at each point along the path. The PathPoint class is a simple data structure that just holds an x/y location, optional control point information (for curves), and the operation that tells the path containing that path point how to nagivate the interval leading up to that point. There are three factory methods that AnimatorPath uses to construct PathPoints as its API is called:
    public static PathPoint moveTo(float x, float y);
    public static PathPoint lineTo(float x, float y);
    public static PathPoint curveTo(float c0X, float c0Y, float c1X, float c1Y, float x, float y);

All of the logic of actually animating between points along the path (besides that in the Android Animator engine itself) is in the class PathEvaluator. This class implements the single method in the TypeEvaluator interface, evaluate():
    public PathPoint evaluate(float t, PathPoint startValue, PathPoint endValue) {...}
The return value of evaluator() depends on the operation described by the endValue PathPoint object.

For curves, we calculate the x/y values given the anchor points (the location at startValue and endValue) and control points (both control points are stored in the endValue structure).
    if (endValue.mOperation == PathPoint.CURVE) {
        float oneMinusT = 1 - t;
        x = oneMinusT * oneMinusT * oneMinusT * startValue.mX +
                3 * oneMinusT * oneMinusT * t * endValue.mControl0X +
                3 * oneMinusT * t * t * endValue.mControl1X +
                t * t * t * endValue.mX;
        y = oneMinusT * oneMinusT * oneMinusT * startValue.mY +
                3 * oneMinusT * oneMinusT * t * endValue.mControl0Y +
                3 * oneMinusT * t * t * endValue.mControl1Y +
                t * t * t * endValue.mY;
    }
For lines, we perform a simple linear interpolation between the start and end points:
    else if (endValue.mOperation == PathPoint.LINE) {
        x = startValue.mX + t * (endValue.mX - startValue.mX);
        y = startValue.mY + t * (endValue.mY - startValue.mY);
    }
For moves, we simply jump to the location defined by the end value:
    else {
        x = endValue.mX;
        y = endValue.mY;
    }
Finally, we create a new PathPoint with this calculated xy information, which will be passed to the setButtonLoc() method seen above:
    return PathPoint.moveTo(x, y);

... and that's it. There's really not much to it, which was the whole point of posting this code. If you want to add curved motion to your animations, you can wait for the framework to do it for you... or you can take what I've done here and modify it to suit your needs. Yay, TypeEvaluator!

I've posted the code on code.google.com; check it out for yourself. Or you can download the Eclipse project (including the pre-built apk) here.