Android – Live Wallpaper part 2

March 22nd, 2012 by Paul Gregoire

Let’s make the star that we created in part 1 rotate in just a few simple steps. Although before we start, I’d like to note that we are technically rotating the entire canvas and not just the star itself; adding more than one star to the display will clearly expose this minor detail. I’ve done some research on the rotation of multiple individual items at-once, but I have not yet found a solution that fits; feel free to comment if you are aware of how to accomplish it.

The code modifications below are being in the LiveWallpaper.java source file, we are not using the only other source file GoldstarActivity.java at this time.

1. Add a variable where we keep track of the first frame drawn. This will prevent some calculations from being executed more than once per instance.

2. To rotate the star, we will use degrees. In steps 2 and 3, two methods of generation are shown. In this section we use a float counter for degrees of rotation.

3. In this section we use a fixed array for degrees of rotation. To do so, we also must create an index counter and an array of 360 floats; again, its up-to-you as to which option to use.

4. If using the array method, the onCreate method is modified to pre-fill our array when the application is first initialized.

Note: I’ve tried both methods for degree cycling and they seem equally fast on my device.

4. Modify our drawing code from part 1. The code block is here for reference.

Before

After (using float counter)

After (using float array)

6. As an aside to what we done thus far, you can easily add another star with a couple extra lines like so:

The additional star will be down and to the right of the primary star. This star will not rotate per-se but instead will “orbit” the primary star.

7. Last step, build and run in the emulator. Right click on the goldstar project in Package Explorer and select Run As -> Android Application. If you haven’t created any AVD (virtual devices), you’ll be prompted to create one. Creation of an AVD is covered here.

When everything works, you’ll see this in the Eclipse console:

I recorded the emulator running the apk in this screencast

Running on my Galaxy Nexus

In the sample code, I’ve refactored the original class alittle to make things more clear.
Project Source

End of part two.

, , , ,

Android Graphics and Animation: Part II – Animation

July 19th, 2011 by Keith Peters

Android Animation

In the first part of this series, we covered basic graphics in Android – starting a new Android project, creating a custom view and displaying it, and using that view to draw custom graphics in its onDraw method. To recap, the drawing occured only when the onDraw method was called by the system when it determined that the app needed to refresh its display. This generally occurs once when the app starts and only occasionally, if ever, thereafter. For animation, we need to be able to trigger redraws on a regular basis. This is quite a bit more complex than drawing a static image, but not horribly so, so let’s dive in.

SurfaceView

In the last example, we extended View for our custom view class. That was fine for the purpose, but will not be adequate for drawing multiple times like we need to do for animation. For View, the onDraw method is triggered by the system when it knows that the Canvas is safe to draw on. It can set things up for us before calling onDraw, and then clean up when it is done executing. Since we need to do drawing on our own schedule, we need a view class that will let us do this set up and clean up ourselves. That class is called SurfaceView. So that’s what our new view will extend.

To get started, create a new Android project the same way we did last time. Call the project and activity “Animation”. Again, in the main activity class replace the call to setContentView with a custom view. We’ll call this AnimView:

Of course, AnimView does not exist, so we’ll get an error. Trigger a quick fix, which will offer to create the AnimView class. Before accepting the defaults in the New Java Class dialog, change the superclass field to “android.view.SurfaceView”. When the class is created, trigger another quick fix to create the constructor. You should end up with the following:

At this point, the app should compile and run, but naturally will show just a black screen.

SurfaceHolder

Again, since we will be a lot more in control of when things get drawn, we need to go a little more low level in what we are doing. When using onDraw, you are automatically passed a Canvas object that you are safe to draw on. When using SurfaceView though, you need to get your canvas from something called a SurfaceHolder. This can be retrieved by simply calling getHolder() from the SurfaceView instance. That’s easy enough, but there’s another bit of complexity coming up.

You can’t draw to a surface of a SurfaceView/SurfaceHolder until the surface is created. And you should not draw to it after it has been destroyed. So we need to know when these things happen. To do that, we can let the holder know that we want to handle related events. To do this, we call surfaceHolderInstance.addCallback(viewInstance). But one more catch – the object you pass to this method must implement an interface defined as SurfaceHolder.Callback. So our class definition starts out as:

public class AnimView extends SurfaceView implements SurfaceHolder.Callback {

When you do that, you’ll be informed that you are not implenting the required methods of that interface. Use a quick fix to add them. With all that done, you should have the following:

Threading

Now we can start animating. In animation, you need generally have some kind of model of what you are animating, with some kind of rules on how that model changes. you need to update the model, and then render that model to the display, then update the model again, render again, and so on.

If you are used to animating in Flash you’re familiar with doing this via enterFrame, or perhaps with timers. Timers are also used in JavaScript animation. In Android though, we generally use threads.

Threads can be a bit scary as they are a bit more complex than a simple timer. If you’re not familiar with threads, the concept is just that you are starting another process that runs independently from the main process. This is useful for operations that might take a long time or will not return immediately. The new thread does its own thing in its own time frame, and the main process of your app continues to do what it needs to do, remaining responsive, etc.

The scary part of threads is that they run separately, but are able to access the same variables and objects in a non-synchronized way. Thus, one thread might be performing some procedure on a given object, and right in the middle of tht procedure, the other thread might step in and change the state of that object or even delete it. So you have to take some extra steps to guard against these types of situations.

Our view will use a separate thread to perform its animation. We will create and start the thread running in the surfaceCreated method, and we will stop the thread in the surfaceDestroyed method. There are a number of different ways to use threads. The way we’ll do it is to subclass the Thread class and put the custom functionality in that class.

Here’s the start of our custom thread class:

In order to draw to a canvas, we’ll need the surface holder to get the canvas from, so we’ll pass that in in the constructor and save it. We’ll also need a variable that will indicate whether or not the thread is currently running and a way to set that.

When we create an instance of this thread class and call start() on it, its run method will be executed in a separate process. We’ll actually use a while loop to do our animation. This may seem odd if you’re coming from the Flash or JavaScript world, where in infinite while loop would just lock things up. But because this is in a separate thread, it works out fine.

The pseudocode for what we will do is like this:

This will just run forever. Well, until we set running to false anyway. As you might have guessed, we’ll create and start the thread in the surfaceCreated method and we’ll set running to false in the surfaceDestroyed method. There’s a few more details to it, but we’ll get there eventually.

Locking and Unlocking

To get a canvas from a surface holder, we actually call holder.lockCanvas(). This prevents anything from happening to the canvas while we are using it. When we are done with our drawing, we call holder.unlockCanvasAndPost(canvas), passing in the canvas instance we just drew to. This frees it up and displays what was just drawn.

Here is the final code with some actual animation going on:

Here you can see we declare the canvas variable, then we enter a try block where we get the canvas and do the drawing. This allows us to unlock the canvas in a finally block, so that even if an exception is thrown while drawing, we won’t leave the canvas in locked state.

Note that the drawing is done in a synchronized block. This puts a lock on the holder so that nothing else can change it from another thread while we are using it. In this block we set the background to black and draw a white circle. The x value will be incremented on each loop, moving the circle across the screen.

Starting and stopping the thread

All we have to do now is create, start, and stop this thread. We’ve already said that we’ll do that in surfaceCreated and surfaceDestroyed methods. So let’s see what this looks like. First the created:

Simple enough. We create the thread, passing in the suface holder, set running to true, and start it. This will wind up executing the run method, which will run that for loop in a separate process.

The destroyed method is a bit more complex:

First of all, we set running to false. This will allow the while loop in the run method to exit. But since that’s happening in another thread, we don’t know exactly when that’s going to happen. So we want to make sure that it’s really fully complete before we leave here. We do that with the join method of the thread. That will cause execution to stop and wait for that thread to end. However, this will sometimes result in an InterruptedException. So we throw that whole thing in a try/catch statement and keep retrying it until the join finally successfully returns. Here’s the final AnimView class:

, , , ,