teaching machines

CS 491 Lecture 4 – XML layouts and widget event handlers

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

Before This Class

Today we’ll dive into our first widget-driven app. By widget, I mean a stock interface element, like a button, a slider, or text field. Up till now we’ve stuck with Canvas and done custom drawing. It’s time to move on. The app we’ll create is one I pulled from Travis’ TODO homework: we’ll create a score card for the card game 7 Wonders.

Note that I’ve never played this game. I found scoresheets online and they seemed fairly simple. The official rules, however, made it sound far more complex. We’re going to appify the simple scoresheets I found, and Travis can tell us where we went wrong. Here’s a sample scoresheet:

[show scoresheet]

Each column is a player. Up to seven can play. Each row is a point category. Red is for battle points. Next is the number of coins. Every third coin is a point, so we’ll have to do arithmetic there. Next is the number of wonders we built. Then we have several rows for building civilian structures, commercial structures, guilds, and some mystery row I don’t understand. We’ll call them green points. The last row, with that sigma, contains a sum of the points tabulated in the rows above.

When I look at this scoresheet, it seems like too much to show at one time on a small device. A tablet maybe, but perhaps not a phone. For now, let’s focus on showing just one player at a time.

A

Before next lecture:

You, group A, are going to explore writing event handlers for a few widgets. It’s generally a good idea to separate our code that has nothing to do with the user interface into standalone code. Let’s do that first. We’ll make a model class with instance variables for the numbers of battle points, the number of coins, wonders, civilian structures, commercial structures, guilds, and green points. Eclipse can generate our getters and setters. We just need to add a getTotalPoints method.

With the number of coins, only every third coin is a point. If we divide by int 3, we’ll get the floor of that division, which is what we want. For instance 10/3 is 3.3333, but the integer division yields the correct value of 3.

What’s nice about keeping the model separate from the user-interface is that it can be independently tested. If this code was caught up in a sick relationship with our view classes, verifying our calculations would be painful.

Our Activity has two tasks initially: breathe life into our model [new Model()] and breathe life into our layout. Your partner is learning about creating the layout as a resource instead of in code. We will take that resource and inflate it from XML with a call to setContentView. After this point, and only after this point, we can grab handles onto the widgets that were defined in the layout resources. Here’s how we do it. [call findViewById]

findViewById gives us back a reference of type View. Under the hood it may be any one of a number of stock widgets or our own custom subclass. We’ve got to cast it to the correct type before we can access its custom behaviors.

For EditText, the handler we provide must be an implementation of the TextWatcher interface.

One of you asked last class about the role of inheritance in Android. The deal is this: the operating system is in control. It gets all the events and does all the orchestrating. The operating system code was written years ago, in many cases. Our code, which is responding to these events, was written today. How can the operating system call our code? The idea is for the operating system to define an intermediate interface that it knows about and can call the methods of. If we conform to that interface, we can have the OS really be calling our code. It’s slick.

Case in point, when the number of battle points gets edited, the OS knows that it happens. We want to catch that event and update our model. We create some code that satisfies the TextWatcher interface, updates the model, and in turn, updates the Total EditText.

Let me offer a quick note on the error we’re seeing here. When our inner classes reference local variables in our methods, Java requires that these be marked final. Why? Because the Java folks think you might get confused about which objects you’re working on. If later in the method we reassign our EditText reference, you might think you’d be working with the altered reference. That’s not true. Our inner class gets a copy of the reference at the time it is instantiated. Sometimes this notion is called a closure. If we change the reference later in the method, we only change the method’s copy, not the inner class’s. Java decided to outlaw the possibility of reassigning the reference so we didn’t get confused.

We do the same for the remaining EditTexts.

TextWatcher is just one type of event-handling interface. Suppose the layout designer also added a clear button to zero everything out. Probably we should add a method to our model to support this. We can add an event-handler by making our event-handling code conform to the onClickListener interface.

All right. We’ve had just a simple peak at event-handling. See you next time.

B

Before next lecture:

You, group B, get to explore designing the interface. Let’s sketch out the idea:

[draw picture of interface]

To construct this interface in Swing, we’d first instantiate a layout manager and then add our widgets to it. A layout manager is the thing that spatially arranges our widgets in a neat way. Android has them too. Common ones include LinearLayout which lays widgets our in a horizontal or vertical line, TableLayout which is a little like an HTML table, and FrameLayout, which lets you draw views on top of one another. That’s nice if you want a button on top of a canvas.

We could create out layout in code. But the preferred method is to construct interfaces in a declarative fashion using XML. You should ask yourself why. The answer is in last week’s videos.

For this particular layout, I’m thinking a GridLayout would be nice. Let’s open up the default layout that the Eclipse tools generated for us. It uses a RelativeLayout, which is cool and lets you position and size widgets relative to one another. It is not a good one to start with. In fact, really we should start with LinearLayout. Oh, well. GridLayout, here we go.

The Eclipse tools provide a visual editor that we will use for some tasks. We computer scientists like control, but we’re not averse to saving time. I’ll drag a GridLayout onto my interface. Now I’ll switch to XML.

We want two columns in our grid. One for labels, and one for text fields.

Let’s start by putting in a big old label on the top saying Player #. For that we use a TextView, much like a JLabel in Swing. Hmm… It should probably span across both columns. Good news. GridLayout is a lot like an HTML table too and we can set an attribute.

The text attribute is where we enter the label’s text. But whoa! Not literal text. We want to sell our app to the developing world, and support as many locales as possible. We make a string value for the label text.

In class