Chapter 6
In This Chapter
Improving the look of an app
Helping people in other countries use your app
Getting your app to communicate with the outside world
Face it — the app in Chapter 5 of this minibook is boring! Really boring! Who wants to click a button to see the words Pepperoni Extra Cheese on a device’s screen?
In this chapter, you improve on the app that you created in Chapter 5. I can’t promise instant excitement, but with modest effort, you can add features to make the app more interesting. (I confess: In this chapter, the real reason for making the app interesting is to show you some additional Android developer tricks. Anyway, read on …)
In addition to being boring, the app in Chapter 5 is ugly. You can improve an app’s look in two ways — the way it looks to a user and the way it looks to another developer. In this section, you do both. When you’re done, you have a layout like the one in Figure 6-1.
Before creating the layout’s code, I want to make some observations about the layout in Figure 6-1:
You may wonder why I make these five observations and not others. If so, read on.
Launch Android Studio and create a new Android project.
For details on creating a new project, see Chapter 3 of this minibook.
In the Designer tool’s preview screen, select the Hello World! text view.
It’s time to get rid of this silly text view.
Press Delete.
Goodbye world!
You want something that aligns objects vertically so that the button is below the pair of check boxes.
Click the LinearLayout (Vertical) element in the palette’s Layouts group. Then click in the preview screen.
As a result, the new LinearLayout (Vertical) element’s outline appears on the preview screen.
Click the Button element in the palette’s Widgets group. Then click inside your vertical linear layout element in the preview screen.
Voilà! Your app has a button.
Next, you want something that aligns objects horizontally so that the check boxes are side by side.
Click the LinearLayout (Horizontal) element in the palette’s Layouts group. Then click inside your vertical linear layout element in the preview screen.
Try to place the horizontal linear layout element above the button. If you have trouble doing that, go to the Component tree and drag the LinearLayout (Horizontal)
branch so that it’s above the button
branch but still subordinate to the LinearLayout (Vertical)
branch. (See Figure 6-2.)
Next, you put the check boxes into your horizontal linear layout.
Click the CheckBox element in the palette’s Widgets group. Then, click inside the horizontal linear layout element in the preview screen.
If you have trouble clicking inside the horizontal linear layout, place the check box anywhere on the preview screen. Then, in the Component tree, drag the checkBox
branch so that it’s subordinate to the LinearLayout
(Horizontal)
branch.
Click the CheckBox element in the palette’s Widgets group again. Then click in the preview screen to the right of the first check box.
Like the first check box, this second check box is inside your horizontal linear layout.
The button and the two check boxes might not be centered side by side on the screen. You want to fix that, and I show you how in the next step.
In the Component tree, select your horizontal linear layout element.
You can try selecting this element in the preview screen but, for an element with nothing but a border, it’s easier to do the selecting in the Component tree.
In the Properties panel, look for the gravity
entry.
Don’t confuse the layout:gravity
entry with the gravity
entry. They’re two different rows in the Properties tree. One of them (the layout:gravity
entry) is associated with an android:layout_gravity
attribute in the layout’s XML code. The other (the gravity
entry) is associated with an android:gravity
entry in the layout’s XML code. (I know. This couldn’t be more confusing. With any luck, the material in Book IV, Chapter 1 can help you sort it all out.)
In the Properties panel, the gravity
entry is a branch of a tree. Expand this branch and put a check mark in the center_horizontal
item within that branch.
The gravity
property helps determine the positions of objects inside a layout (in this example, inside your horizontal linear layout element). The gravity
value center_horizontal
centers objects side by side within the layout. After checking the center_horizontal
item, notice that the two check boxes are centered (side by side) in the preview screen.
In the Properties panel, expand the vertical linear layout element’s gravity
branch. Put a check mark in the center_horizontal
item within that branch.
When you do this, the button snaps sideways to the center of the preview screen.
The vertical linear layout element holds the check boxes and the button, but there’s another widget in Figure 6-1. (It’s a TextView displaying the word Plain.) To make room for this additional widget, you want to tell Android that the vertical linear layout doesn’t fill up the entire screen. The next step tells you how to do that.
layout:height
entry in the Properties panel.Click in the right column of the layout:height
entry. In the drop-down list that appears, select wrap_content
.
As a result, your vertical linear layout element shrinks so that it’s large enough for only the two check boxes and the button.
You have a bit more work to do, but the work isn’t burdensome.
Change the text on the check boxes and the button so that it matches what you see in Figure 6-1.
Don’t worry about the word Plain in Figure 6-1. You work on that in the section “Reusing a layout,” later in this chapter.
For help changing the text, see to Chapter 5 of this minibook.
Set the onClick
property of the button to onButtonClick
.
For help setting the onClick
property, see Chapter 5 of this minibook.
The check boxes and the button in Figure 6-1 are useful in more than one situation. You might place these widgets in an app with a confirmation word (such as the word Plain in Figure 6-1). You might use the same widgets in a different app with a picture of a pizza below the widgets. One way or another, it’s worth your while to save the layout containing these widgets. You save these widgets in a new layout resource document (a blahblah
.xml
document in the res/layout directory). This section tells you how to do that.
In the preview screen, click in a neutral place inside the vertical linear layout that you created.
Make sure that you see the outline of the layout that contains both check boxes and the button. If you have trouble selecting this layout, you can ignore the preview screen and select the LinearLayout (Vertical)
branch in the Component tree.
In Android Studio’s main menu, choose Refactor ⇒ Refactor This.
A pop-up menu containing the Style and Layout options appears.
In the pop-up menu, select Layout.
An Extract Android Layout dialog box appears.
In the dialog box’s File Name field, type the name of your new resource document.
In Figure 6-3, I type reusable_layout.xml.
The names of Android’s resource files must not contain capital letters. You can use lowercase letters and underscores. You cannot use Java’s customary “camelCase” naming convention with names like reUsableLayout.xml
. And, yes, a layout filename must end with the extension .xml
.
Click OK to close the dialog box.
The app/res/layout
branch in the Project tool window now has a new item. If you named the file as I did in Step 5, the branch is labeled reusable_layout.xml
.
Double-click the reusable_layout.xml
branch in the Project tool window.
Android Studio displays the Designer tool for the reusable_layout.xml
file.
Make sure that the Designer tool is in Design mode (as opposed to Text mode).
In Design mode, you can see the Component tree.
Make note of the labels on the branches in the Component tree.
Look for names like checkBox
, checkBox2
, and button
. (See Figure 6-4.) You use these names (these id values) in the code that you write later in this chapter.
To change an element’s id, double-click that element in the preview screen. The resulting pop-up menu has a text field labeled id. Change whatever is entered in that text field.
Congratulations! You have a group of widgets that you can use and reuse.
In the “Creating a reusable layout” section, you create a layout with check boxes and a button. You can reuse this layout in many of this chapter’s examples. Here’s how:
Follow the steps in the “Creating a reusable layout” section.
If you’re impatient, you can skip a few of that section’s steps, but be sure to create a reusable_layout.xml
file and to populate the file with a few widgets.
reusable_layout.xml
file.In Android Studio’s main menu, choose Edit ⇒ Copy.
You don’t see much happening, but now your Clipboard contains a copy of the reusable_layout.xml
file.
app/res/layout
branch.In Android Studio’s main menu, choose Edit ⇒ Paste.
Now the app/res/layout
branch contains a reusable_layout.xml
file.
Open your project’s res/layout/activity_main.xml
file.
When you do, you see your new project’s preview screen (which is mostly empty).
In the Custom group in the Designer tool’s palette, click the <include> item.
The palette has its own scroll bar. Use this scroll bar to find the palette’s Custom group.
When you do this, a Resources dialog box appears. (See Figure 6-5.)
In the Resources dialog box, select your reusable layout — the one you named reusable_layout.xml
; then click OK.
The Resources dialog box closes.
Click in the Designer tool’s preview screen.
As if by magic, the stuff that you created in the “Creating a reusable layout” section appears on the preview screen. (Well, anyway, it looks like magic to me.) This stuff appears as one group, so you can drag that group around in the preview screen.
If necessary, reshape the newly included group (two check boxes and a button) by dragging its edges in the preview screen. Also, drag the entire group so that it’s centered inside the preview screen.
If all goes well, your layout looks like the stuff in Figure 6-1.
In the next step, you add the word Plain to your app’s screen. (Refer to Figure 6-1.)
(Optional) If you’re very ambitious, follow the steps in Chapter 5 of this minibook for coding your app’s behavior. Then run your app.
Ambitious or not, you have a decent-looking layout with a reusable component. Nice work!
As I mention in Chapter 4 of this minibook, an Android activity is one “screenful” of components. So juggling activities is a major endeavor for Android developers. This section’s example does the simplest thing you can do with an activity — namely, make it run.
Launch Android Studio and create a new project.
In this section’s listings, I name the application 01_06_01
, and I name the package com.allyourcode.p01_06_01
.
Follow the instructions in the earlier section “Reusing a layout” to include reusable_layout
on your new app’s screen.
You have two check boxes and a button. When a user clicks the button, you want Android to display a different activity’s screen. So you have to create another activity.
Let’s get cracking …
In the Project tool window, right-click or (on a Mac) Ctrl-click your project’s app/java/
your.package
branch.
In Listing 6-1, the package name is com.allyourcode.p01_06_01
. So I Ctrl-click my project’s app/java/com.allyourcode.p01_06_01
branch.
In the context menu that appears, choose New ⇒ Activity ⇒ Blank Activity.
A dialog box appears. (You see this dialog box whenever you create a new blank activity. The dialog box is labeled Choose Options for Your New File.)
In the dialog box, fill in the Activity Name and Layout Name fields.
In Listings 6-1 and 6-2, I refer to OtherActivity
and other_layout
. So, if you’re following along letter for letter with these instructions, type OtherActivity in the Activity Name field, and type other_layout in the Layout Name field. You can accept the defaults for all the other fields in the dialog box.
Click Finish to close the dialog box.
Your new other_layout
now appears in Android Studio’s Designer tool.
(Optional, but worth doing.) In this step, you don’t have to do anything. Just look at something! In your project’s AndroidManifest.xml
file, notice the following code:
<activity
android:name=".OtherActivity"
android:label="OtherActivity" >
</activity>
Android Studio added this <activity>
element when you created OtherActivity
in Steps 3 through 6.
Each activity in your application must have an <activity>
element in the AndroidManifest.xml
file. In an <activity>
element, the android:name
attribute points to the name of the activity’s Java class. In this step, the attribute’s value is “.OtherActivity"
. The initial dot refers to the application’s package name (the name com.allyourcode.p01_06_01
from Step 1). The rest of the attribute refers to the class name in Listing 6-2.
Each activity in your application must have an <activity>
element. If you’re missing an <activity>
element, the app can’t start that activity. (Instead, the app crashes, and you see an Unable to find explicit activity message in the Logcat panel.)
With other_layout
showing in the preview screen, drag a Large Text element from the palette onto other_layout
.
Now, other_layout has a TextView element (with large text).
Your project has two activities (two Java files) and a layout for each activity (two XML files in the Project view’s app/res/layout
branch). In addition, your project has a reusable_layout
that’s included inside your main activity’s layout. You can switch back and forth between the two activities and their layout files, but try to be mindful of the switching. Try not to be become confused by editing the wrong Java code or the wrong layout file (the way I often do).
Look for your new TextView element in the Component tree.
Make note of the label on that element’s branch of the tree. In my version of the app, the label is textView3
.
If you switch momentarily to the Designer tool’s Text mode, you see the attribute android:id="@+id/textView3"
inside the TextView
tag. The id of this element is textView3
.
To change an element’s id, double-click that element in the preview screen. The pop-up menu that appears has a text field labeled id. Change whatever is entered in that text field.
Modify your main activity’s code, as shown in Listing 6-1.
I set the code to be added in boldface type.
Double-check the expressions R.id.checkBox
and R.id.checkBox2
in Listing 6-1 against the names in the Component tree at the end of the “Creating a reusable layout” section. If the Component tree’s labels aren’t checkBox
and checkBox2
, change your Listing 6-1 code appropriately.
In the MainActivity
(Listing 6-1), you have code that starts up the OtherActivity
. You don’t start an activity by calling the activity’s methods. Instead, you create an intent. An intent is like an open-ended method call. In Listing 6-1, you create an explicit intent — an intent that invokes a specific class’s code.
OtherActivity
(or whatever you name your app’s second activity).pepBox.isChecked()
is true
, so the intent contains the extra pair "Pepperoni", true
.startActivity(intent)
invokes the OtherActivity
class’s code.This section’s explanation of Android’s intent mechanism shows you the tiniest tip of the iceberg. To read all about activities and intents, see Book III, Chapter 2.
Next up, your OtherActivity
should have some code that responds to the fact that OtherActivity
was started.
In your new OtherActivity
class, add the code in Listing 6-2.
I set the code to be added in boldface type.
In Listing 6-2, I assume that the TextView
in the other_layout.xml
file is textView3
. (That is, I assume that, in the XML file itself, the TextView element has an attribute that reads android:id="@+id/textView3"
.) If this TextView element has an id other than textView3
, change the code in Listing 6-2 accordingly.
In Listing 6-2, the call to getIntent
gets the stuff that started this activity running. So, by calling getIntent
and intent.getBooleanExtra
, the OtherActivity
discovers the values of pepBox.isChecked()
and cheeseBox.isChecked()
from Listing 6-1. For example, the call
intent.getBooleanExtra("Pepperoni", false)
returns true
if the value of pepBox.isChecked()
in Listing 6-1 is true
. The call returns false
if the value of pepBox.isChecked()
in Listing 6-1 is false
. The call’s second argument is a default value. So, in Listing 6-2, the call to intent.getBooleanExtra("Pepperoni", false)
returns false
if the intent created in Listing 6-1 doesn’t have an extra named "Pepperoni"
.
Run your app.
When you click the app’s button, you see a new activity like the one pictured in Figure 6-6.
Listing 6-1: Starting OtherActivity from the MainActivity
package com.allyourcode.p01_06_01;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.CheckBox;
public class MainActivity extends Activity {
CheckBox pepBox, cheeseBox;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
pepBox = (CheckBox) findViewById(R.id.checkBox);
cheeseBox = (CheckBox) findViewById(R.id.checkBox2);
}
public void onButtonClick(View view) {
Intent intent =
new Intent(this, OtherActivity.class);
intent.putExtra
("Pepperoni", pepBox.isChecked());
intent.putExtra
("Extra cheese", cheeseBox.isChecked());
startActivity(intent);
}
// You don’t have to add any code below this point
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// … Et cetera
Listing 6-2: The OtherActivity
package com.allyourcode.p01_06_01;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
public class OtherActivity extends Activity {
TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.other_layout);
textView = (TextView) findViewById(R.id.textView3);
Intent intent = getIntent();
StringBuilder str = new StringBuilder("");
if (intent.getBooleanExtra("Pepperoni", false)) {
str.append("Pepperoni ");
}
if (intent.getBooleanExtra("Extra cheese", false)) {
str.append("Extra cheese");
}
if (str.length() == 0) {
str.append("Plain");
}
textView.setText(str);
}
// You don’t have to add any code below this point
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// … Et cetera
Words, words, words. The apps in this chapter have so many words. "Pepperoni"
here; "Extra cheese"
there! It’s a wonder a developer can keep this stuff straight. It’s too easy to type a word one way in one part of the code and misspell the word in a different part.
You can reduce the problem by creating string constants. For example, you can write
public final String pep = "Pepperoni";
at the top of your Java program and use the variable pep
in place of the string "Pepperoni"
throughout the code. But then, to change from the English word pepperoni to the Italian word merguez, you have to mess with your Java code. In a world where only six percent of all mobile phones are in the United States,* you don’t want to edit Java code for dozens of countries.
The elegant solution to this problem is to use Android’s string externalization feature. Here’s what you do:
Open the project that you created in this chapter’s “Reusing a layout” section.
If you’ve messed with that project since you created it, or if you didn’t faithfully execute each of my instructions in that section, don’t despair. You can find that project in the stuff that you download from my website. Visit http://allmycode.com/android
and follow the instructions in Chapter 3 of this minibook for running the downloaded examples.
Open the project’s reusable_layout.xml
file and put the Designer tool in Text mode.
Notice lines such as
android:text="Extra cheese"
in the reusable_layout.xml
file? What if the user isn’t an English language speaker? A layout file describes the look of the app’s screen. The look of the screen shouldn’t depend on the user’s being able to understand what Extra cheese
means.
"Extra cheese"
.Press Alt-Enter.
A pop-up menu appears. This menu is called an intention action menu. The menu contains a list of actions from which you can choose.
In the intention action menu, select Extract String Resource.
Well, wha' da' ya' know?! An Extract Resource dialog box appears! (See Figure 6-7.)
In the Resource Name field, type extra_cheese.
A resource name must not contain blank spaces. In this step, extra_cheese
is okay and extracheese
is also okay. But extra cheese
isn’t okay.
Click OK.
Android Studio adds the following element to your res/values/strings.xml
file:
<string name="extra_cheese">Extra cheese</string>
Android Studio also replaces "Extra cheese"
in your layout’s CheckBox element with an @string
expression:
<CheckBox
android:text="@string/extra_cheese"
(Optional, but very nice if you do it.) Repeat Steps 3 through 7 for the strings "Pepperoni"
, "Show"
, and (in the activity_main.xml
file) "Plain"
.
With your app’s strings externalized, you’re ready to go international.
strings.xml
file in your project’s res/values
folder in the Project tool window.In the context menu that appears, select Open Translations Editor.
The Translations Editor appears in place of the Designer tool. (See Figure 6-8.)
Near the top of the Translations Editor, click the globe icon.
A list of language locales appears. (See Figure 6-9.)
Select a language locale from the list.
For this exercise, I select Italian (it). (I’d be disloyal to my buddy Steve if I did otherwise.) For the full scoop on language locales, visit www.iso.org/iso/country_names_and_code_elements
.
As a result, the strings.xml
branch in the Project tool window now has two sub-branches. Both sub-branches sport the label strings.xml
, but the new sub-branch’s icon is a tiny picture of the flag of Italy. (See Figure 6-10.)
Temporarily change the Project tool window from Android view to Project view. Your project’s res
folder now has a values
subfolder and a values-it
subfolder. The values-it
subfolder contains its own strings.xml
file. (Okay, you can go back to the Android view now!)
In the Translations Editor, the term extra_cheese
is in red because you haven’t yet translated extra_cheese
into Italian. The same is true for other terms that you haven’t yet translated.
Double-click the Italian (it) column in the extra_cheese
row. In that column, type Con più formaggio
, and then press Enter.
(Sorry. The Translations Editor doesn’t do any translating for you. The Translations Editor only adds code to your project when you type in the translations of words and phrases.)
Repeat Step 13 for the pepperoni, show, and plain rows.
If your Italian is a bit rusty, copy the text from the res/values-it/strings.xml
file in Listing 6-3.
Test your app.
As with most devices, the emulator has a setting for Language & Input. Change this setting to Italiano (Italia), and suddenly, your app looks like the display in Figure 6-11.
Elenco 6-3: Benvenuto in Italia!
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">
Ciao mondo, la mia attività!</string>
<string name="app_name">
Il mio secondo progetto Android</string>
<string name="extra_cheese">Con più formaggio</string>
<string name="pepperoni">Merguez</string>
<string name="plain">Semplice</string>
<string name="show">Mostra</string>
</resources>
Why click twice when you can do the same thing by clicking only once? Think about the example in the previous section. Your app responds to the contents of check boxes when the user clicks a button. In a streamlined scenario, your app might respond as soon as the user checks a box. Listing 6-4 shows you how to make this happen.
Listing 6-4: Responding to CheckBox Events
package com.allyourcode.p01_06_04;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.
OnCheckedChangeListener;
import android.widget.TextView;
public class MainActivity extends Activity
implements OnCheckedChangeListener {
TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
((CheckBox) findViewById(R.id.checkBox))
.setOnCheckedChangeListener(this);
((CheckBox) findViewById(R.id.checkBox2))
.setOnCheckedChangeListener(this);
textView =
(TextView) findViewById(R.id.textView);
}
@Override
public void onCheckedChanged(CompoundButton box,
boolean isChecked) {
StringBuilder str =
new StringBuilder(textView.getText());
CharSequence boxText = box.getText();
if (isChecked) {
str.append(" " + boxText);
} else {
int start = str.indexOf(boxText.toString());
int length = boxText.length();
str.replace(start, start + length, "");
}
textView.setText(str.toString().trim());
}
//… Et cetera
Like a button, each check box listens for onClick
events. So you can write this section’s code very much like the code in Listing 6-1. But in this section’s listing, I avoid using the onClick
property and illustrate the use of a different event listener.
A check box listens for changes to its state (its “checked” versus “unchecked” state). So when the user touches a check box, Android fires an onCheckedChanged
event. By registering this
(the entire MainActivity
instance) as each check box’s OnCheckedChangeListener
, you make Android call the onCheckedChanged
method in Listing 6-4.
The onCheckedChanged
method has two parameters — the component that was touched and the state of the component as a result of the touch. I’ve contrived the code in Listing 6-4 to make use of these two method parameters.
In Listing 6-4, the onCheckedChanged
method’s box
parameter refers to whichever check box the user touches. That check box has a getText
method, so in Listing 6-4, I use the getText
method to help fill the textView
element. I use the onCheckedChanged
method’s isChecked
parameter to decide whether to add text to the textView
element or delete text from the textView
element.
After designing an app and its variations in the previous sections, you may decide that your app needs some flair. How about designing your app so that when a user clicks a button, your app displays a picture of the pizza being ordered? The SHOW button in Figure 6-1 is perfect for this.
Android has all kinds of features for drawing images and displaying bitmap files. I cover many of these features in Book IV, Chapter 3. In this section, I cover one possible approach:
Launch Android Studio and create a new project.
In this section’s listings, I call the project 01_06_05
, and I use the package com.allmycode.p01_06_05
.
reusable_layout.xml
file from this chapter’s “Creating a reusable layout” section to your new project’s app/res/layout
branch in the Project tool window.Include reusable_layout
in your project’s activity_main.xml
file.
For details, see Steps 7 through 11 in the section “Reusing a layout.”
Find four images — one for plain, one for pepperoni, one for extra cheese, and one for pepperoni with extra cheese.
Android’s official documentation recommends the .png
format for images. If you don’t have .png
images, Android’s docs call the .jpg
format “acceptable.” If you don’t have .png
or .jpg
, the docs tell you to hold your nose and use .gif
. But remember, in this section, you’re creating a practice application, not a work of art. Your images don’t have to look good. They don’t even have to look like pizzas. Besides, you can download my silly-looking drawings of pizzas from this book’s website at www.allmycode.com/Android
.
In creating my project, I use the filenames plain.png
, pepperoni.png
, extracheese.png
, and pep_extracheese.png
.
The names of Android’s resource files must not contain capital letters. You can use only lowercase letters and underscores.
For working with image formats, the program IrfanView has always served me well. You can get this Windows program at http://www.irfanview.com
. The program is free for noncommercial use.
app/res/drawable
branch.In the main menu, choose Edit ⇒ Paste.
A Choose Destination Directory dialog box appears.
In the Choose Destination Directory dialog box, select the drawable
branch (as opposed to one of the drawable-dpi
branches), and then click OK.
In a real-life app, you use the drawable-dpi
directories as alternatives for devices with high, medium, extra-high, and extra-extra-high screen densities. But in this practice app, a default drawable
folder is the easiest to use.
The letters dpi stand for dots per inch. Android senses a device’s screen density and uses the resources in the most appropriate drawable-?dpi
folder. To find out what Android considers “most appropriate,” visit http://developer.android.com/guide/practices/screens_support.html
.
app/res/drawable
branch.In the menu that appears, select New ⇒ File.
Once again, the Choose Destination Directory dialog box rears its ugly head.
Select the drawable
branch, and then click OK.
A New File dialog box appears. This dialog box has only one field — a field for the name of your new file. (See Figure 6-12.)
Use Android Studio’s editor to populate your levels.xml
file with the code in Listing 6-5.
A level-list is a list of alternative drawables for a single image component to display. At any moment during an app’s run, the image component has an integer level. You set the component’s level using the setImageLevel
method.
When your app calls setImageLevel
, Android starts at the top of the level-list and looks for the first item whose android:maxLevel
is greater than or equal to the new image level. You can also assign an android:minLevel
attribute to an item. But in most situations, android:maxLevel
is all you need.
Add an ImageView element to your activity’s layout.
You can drag an ImageView element from the Widgets group in the Designer tool’s palette, or you can add the following element to your app’s activity_main.xml
file:
<ImageView android:id="@+id/imageView1"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:src="@drawable/levels"></ImageView>
Make sure that your ImageView element’s android:src
attribute refers to your new levels.xml
file.
In the src
entry in the Properties view, look for the value @drawable/levels
.
Code your project’s activity file as in Listing 6-6.
In Listing 6-6, the onButtonClick
method calls the setImageLevel
method. The method parameter’s value depends on the states of the activity’s check boxes.
Run the app.
The results, along with my beautiful drawings of pizza with toppings, are shown in Figure 6-13.
Listing 6-5: A Level-List Document
<?xml version="1.0" encoding="utf-8"?>
<level-list xmlns:android=
"http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/plain"
android:maxLevel="0" />
<item android:drawable="@drawable/pepperoni"
android:maxLevel="1" />
<item android:drawable="@drawable/extracheese"
android:maxLevel="2" />
<item android:drawable="@drawable/pep_extracheese"
android:maxLevel="3" />
</level-list>
Listing 6-6: Changing Images
package com.allmycode.p01_06_05;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.CheckBox;
import android.widget.ImageView;
public class MainActivity extends Activity {
CheckBox pepBox, cheeseBox;
ImageView imageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
pepBox =
(CheckBox) findViewById(R.id.checkBox);
cheeseBox =
(CheckBox) findViewById(R.id.checkBox2);
imageView =
(ImageView) findViewById(R.id.imageView);
}
public void onButtonClick(View view) {
int level = 0;
if (pepBox.isChecked()) {
level += 1;
}
if (cheeseBox.isChecked()) {
level += 2;
}
imageView.setImageLevel(level);
}
// You don’t have to add any code below this point
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// … Et cetera
If you’ve read any of this chapter’s previous sections, you’re probably very hungry. An app with nothing but pictures and the names of pizza toppings is a real tease.
So you’d better add some purchasing power to this chapter’s example. Real e-commerce functionality is the subject of several other books. But in this book, you can get a small taste of the online pizza-ordering process (pun intended). You can submit your choice of toppings to an existing web server — Google’s search engine, to be precise. It’s not as good as biting into a tasty pizza, but the example shows you one way to send information from a mobile device.
In a real application, you might program your own server to respond intelligently to users' requests. For passing money back and forth, you might use the Google Play Store’s in-app billing facilities.
Launch Android Studio and create a new project.
In this section’s listing, I call the project 01_06_07
, and I use the package com.allmycode.p01_06_07
.
reusable_layout.xml
file from this chapter’s “Creating a reusable layout” section to your new project’s app/res/layout
branch in the Project tool window.Include reusable_layout
in your project’s activity_main.xml
file.
For details, see Steps 7 through 11 in the section “Reusing a layout.”
Get a WebView element from the Widgets group of the Designer tool’s palette. Place that WebView element anywhere on your app’s preview screen.
A WebView is a mini web browser that you can add to an existing activity.
It doesn’t matter how you position the WebView element on the screen. When the user visits a web page, the page will take up the entire screen. (If you want the page to appear below your check boxes and button, you’ll have to see Chapter 1 in Book IV.)
Add the following element to your project’s AndroidManifest.xml
file:
<uses-permission
android:name="android.permission.INTERNET" />
Make this uses-permission
element a direct sub-element of the document’s manifest
element.
The uses-permission
element grants your app permission to access the Internet. Access to the Internet will appear in the list the user sees before installing your app.
When you create an app, don’t forget to add the appropriate permissions to the app’s AndroidManifest.xml
file. In a recent survey of For Dummies book authors, all respondents reported that they frequently forget to add permissions to their apps' manifest files. (Survey sample size: one.)
Run your app.
You might have to wait for the web page to load. When the page loads, your app looks something like the screen in Figure 6-14.
Listing 6-7: Sending Info to a Server
package com.allmycode.p01_06_07;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.webkit.WebView;
import android.widget.CheckBox;
public class MainActivity extends Activity {
CheckBox pepBox, cheeseBox;
WebView webView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
pepBox = (CheckBox) findViewById(R.id.checkBox);
cheeseBox = (CheckBox) findViewById(R.id.checkBox2);
webView = (WebView) findViewById(R.id.webView);
}
public void onButtonClick(View view) {
StringBuilder str = new StringBuilder("");
if (pepBox.isChecked()) {
str.append("Pepperoni");
}
if (cheeseBox.isChecked()) {
str.append(""Extra cheese"");
}
if (str.length() == 23) {
str.insert(9, '+');
}
if (str.length() == 0) {
str.append("Plain");
}
webView.loadUrl
("http://www.google.com/search?q="+str.toString());
}
// You don’t have to add any code below this point
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// … Et cetera
3.139.67.5