teaching machines

CS 491 Lecture 3 – Media and Resource Management

September 10, 2012 by . Filed under cs491 mobile, fall 2012, lectures.

Before This Class

A

Before next lecture:

Hey, A. Today we’re going to explore getting Android to play sounds and show pictures. Many of the killer mobile apps these days are rich with media, and in order to reach our first million, we’ll have to know a thing or two about adding this glitz.

Let’s start with sound. I’ve got a mostly empty project here, with just an Activity. Here’s my first goal:

Activity has an onTouchEvent just like View. As someone mentioned in the last class, if you are versed in the model-view-controller design pattern, you might be bothered that two UI (Activity and View) classes handle their own events. It’d be nice to have the handlers pushed out to some intermediate controller class. Good design is a big task. Let’s not tackle it now.

Let’s play an audio file from the web. One class I can use for that is MediaPlayer. The easiest way to make one is to call static method create. We’ve got to give it our context, like most objects that we create, and a path to our sound file. The interface doesn’t allow for a plain String. It requires a URI, which might be an Internet address, a path to a file on the SD card, or various other   data sources. Ours is just a URL, which we can turn turn into a Uri with Uri.parse.

To get it to play, we call the start method.

Here’s an experiment for you to run. When I put code after start(), when is it executed? Answer that question for yourself.

[break]

start() is a non-blocking call. It returns control even before the work of the method finishes. Behind the scenes, it must fire up some thread that runs concurrently with our main thread. This means that even though our player is a local variable, it’s still sitting in memory. We can set up a callback via setOnCompletionListener to free it.

If we fail to do this, we may run out of memory if we play a lot of audio files.

Let’s now move on to showing a picture. There are standard widgets for displaying images, like JLabel in Swing, but we’re going to stick with Canvas for one more day. Let’s make a new View subclass just like we did the other day.

This time, in onDraw, we want to draw a picture. Canvas has several drawBitmap methods. The first parameter is a bitmap, which we don’t have yet. The second are the top-left coordinates where we want the bitmap to appear. The final is a Paint object. For bitmaps, this can be null. If we wanted to apply some sort of  to the bitmap, we’d use paint to do so.  We’ll use null for now and place our image at the top-left. Android, like most GUI libraries but unlike your calculator, considers the origin to be the top-left of the screen. For the bitmap, let’s use the icon for our app. The icon is what’s called a resource. That’s what your partner is learning about. For our purposes, we can load in a bitmap resource with the BitmapFactory class.

One caveat here, which applies to any drawing code. Don’t do I/O or other heavyweight operations in the drawing callback. Try to avoid anything with the new operator. Here, let’s read once in the constructor and store the result to an instance variable.

B

Before next lecture:

B, you drew the resources straw. Today you and I are going to discuss the res directory you see in your project.

Instead of starting with a definition, let’s start with the problem resources solve. Suppose you want to pop up a message when a user resumes an app. You could use a little Toast message. The gotcha is that our literal String here only works for one language. We could fix that by creating a conditional ladder: if we have a Spanish locale, use hola; if French, use bonjour; if Japanese, konnichiwa. While this would work, that’s a lot of mindless coding.

A good software system, be it Android or otherwise, solves this problem by externalizing items like these labels to resources, which are stored not in code but in the res directory. We let the framework decide which resource to draw up based on the device’s configuration, and we just refer to the greeting symbolically. We write no repetitive conditional code.

String resources like our greeting go in the values directory, in strings.xml. We make a new element for our resource, name it, and in our code, we conjure it up with getString(name). That worked for the English version, but what about Spanish? For that, we need a second values directory, this time flagged with -es, for Espanol. We make a custom strings.xml and redefine our resources to their Spanish counterparts.

Now, if we switch our locale, our device’s configuration gets changed. By default, when the configuration changes, our activity is brought down and recreated, which lets the new correct resources get pulled out from the right resource subdirectories.

The next resource we’ll look at is a menu. Menus popup when we hit the menu button in an Activity that overrides a certain callback. Let’s override that method and another one that will get called when a menu item is selected.

Our menu is defined not programmatically, but as an XML resource. We’ll be able to label menu items with string resources. Let’s create two items, one to quit our app and one that will pop up a dialog box. We also need to give each item an identifier, whose role will be seen shortly. The syntax is a little strange.

In-class

With your partner, implement a bubble-wrap popping app. Follow these guidelines:

Your questions