In this series, we are creating a Hangman game for the Android platform. So far, we've built the application's user interface, including images, drawables, and layouts. In this third and final installment, we are going to focus on user interaction.
Introduction
Adding user interaction to the game involves several aspects, including detecting whether the user wins or loses a game as well as responding to each event. We'll also add a help button to the action bar and add the ability to navigate the game.
To refresh your memory, this is what the final game will look like.
1. Prepare the User Interface
Step 1
As we saw in the previous tutorial, the game activity presents the gallows area with the six body parts drawn to the screen. When a new game starts, the body parts need to be hidden, only showing them when the user makes a wrong guess. Open the game's activity class and start by adding the following import statements to it.
1
2
3
4
5
6
7
importandroid.app.AlertDialog;
importandroid.content.DialogInterface;
importandroid.support.v4.app.NavUtils;
importandroid.view.Menu;
importandroid.view.MenuItem;
importandroid.view.View;
importandroid.widget.ImageView;
Next, declare five instance variables in the class's interface.
01
02
03
04
05
06
07
08
09
10
//body part images
privateImageView[] bodyParts;
//number of body parts
privateintnumParts=6;
//current part - will increment when wrong answers are chosen
privateintcurrPart;
//number of characters in current word
privateintnumChars;
//number correctly guessed
privateintnumCorr;
You could change the number of body parts if, for example, you'd like to add several levels of difficulty to the game. By storing the current body part (currPart), we can add one body part at a time in case the player makes a wrong guess. We use the letter count of the target word and the number of right guesses to keep track of the player's progress in the current game. We periodically check if the player has won or lost the game.
In the onCreate method of the game's activity class, right before we invoke playGame, we instantiate the image view array and fetch the body part images we placed in the layout. This code snippet also determines the order in which the body parts are shown when the player makes a wrong guess. We start with the head and end with the legs.
In the playGame method, append the following code snippet. We set currPart to 0, set numChars to the length of the target word, and set numCorr to 0.
1
2
3
currPart=0;
numChars=currWord.length();
numCorr=0;
Before we start the game, the body parts need to be hidden.
1
2
3
for(intp = 0; p < numParts; p++) {
bodyParts[p].setVisibility(View.INVISIBLE);
}
The next screenshot shows how the game should look when a new game is about to begin.
2. Respond to User Clicks
Step 1
When we created the layout for the letter buttons, we declared an onClick method. Let's add this to the game's activity.
1
2
3
publicvoidletterPressed(View view) {
//user has pressed a letter to guess
}
When the player taps a letter button to make a guess, letterPressed receives a reference to the view. This allows us to figure out which letter the player has chosen. To find out which letter the player has tapped, we use the following code snippet.
1
String ltr=((TextView)view).getText().toString();
Next, we get the character from the string.
1
charletterChar = ltr.charAt(0);
We also disable the letter button and update the background drawable to show the player that the letter has already been played.
In the next step, we loop through the characters of the target word to verify whether the player's guess is in it. Each letter of the target word is compared with the player's guess. If the player's guess matches a letter in the target word, we increment numCorr, set correct to true to indicate that the player made a good guess, and update the letter's text color from white to black to make it visible. The for loop continues until every letter of the target word has been checked. This is important as a letter can occur more than once in the target word.
1
2
3
4
5
6
7
8
booleancorrect = false;
for(intk = 0; k < currWord.length(); k++) {
if(currWord.charAt(k)==letterChar){
correct = true;
numCorr++;
charViews[k].setTextColor(Color.BLACK);
}
}
Step 2
Next, we need to verify whether the player has won or lost the game after their guess, or made a wrong guess but can still continue. Still inside letterPressed, start by checking if the player has made a good guess.
1
2
3
if(correct) {
//correct guess
}
If she did make a good guess, check if she's guessed all the letters of the target word.
1
2
3
if(numCorr == numChars) {
//user has won
}
If this is true, we notify the player that she's won the game. The first thing we do is disabling the letter buttons. We do this by implementing another helper method,disableBtns. Implement this method after letterPressed.
1
2
3
4
5
6
publicvoiddisableBtns() {
intnumLetters = letters.getChildCount();
for(intl = 0; l < numLetters; l++) {
letters.getChildAt(l).setEnabled(false);
}
}
In disableBtns, we loop through the views via the adapter and disable each button. If the user has won the game, we invoke disableBtns and display an alert dialog to the user. In the alert dialog, we also ask the player if they want to play another game.
Take a moment to look over this if you're not familiar with dialogs on Android. We set the properties including title and a message including confirmation of the correct answer. We add a button to play again to the alert dialog, which calls the playGamemethod. We also add a button to exit, which takes the player back to the main activity.
If the user hasn't won the game, we need to verify if she has answered incorrectly, but still has some guesses left. Inside the else if block, we show the next body part and increment the number of incorrect guesses with 1.
1
2
3
4
5
6
7
8
if(correct) {
//correct guess
} elseif(currPart < numParts) {
//some guesses left
bodyParts[currPart].setVisibility(View.VISIBLE);
currPart++;
}
Step 4
After the else if, we can safely assume that the player has lost the game. We start by disabling the buttons as we did earlier and we display an alert dialog stating that the player has lost the game. We also include the correct answer and offer the option to play another game.
Believe it or not, we're done implementing the user interaction aspect of the game. All that's left for us to do is add a few enhancements to the interface.
3. Complete the Action Bar
Step 1
Let's finish up this tutorial by adding a help button to the action bar. I won't go into too much detail, but feel free to experiment with this in your own applications. Depending on the API levels you target, support for navigating by means of the action bar is provided with little or no coding. To ensure the action bar allows navigating back to the main activity, add the following inside the onCreate method in the game's activity.
1
getActionBar().setDisplayHomeAsUpEnabled(true);
In the manifest, remember that we specified the main activity as the parent of the game's activity. This tells the operating system that navigating back/up from the game's activity should bring the user back to the main activity. Your project should have a main menu resource. Open it and take a look at its contents. By default, it will have a settings action, which we don't need for our game. Insert the following code snippet, to add a help button.
1
2
3
4
5
<item
android:id="@+id/action_help"
android:icon="@drawable/android_hangman_help"
android:showAsAction="ifRoom"
android:title="help"/>
Remember that we listed the help icon in the first tutorial of this series. You can add more buttons to your action bar later if you like. If you do, you'll need to extend the activity code we cover below.
We don't need the action bar functions in the main activity so if Eclipse added theonCreateOptionsMenu method to your main activity class, feel free to remove it.
Step 2
Back in the game's activity, set the screen to use the main menu by adding the following method.
1
2
3
4
5
@Override
publicbooleanonCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
returntrue;
}
Add another method to specify what should happen when the user tries to navigate back/up or press the help button in the action bar.
Navigating up will take the user back to the main activity. The android.R.id.homeaction corresponds to the call to setDisplayHomeAsUpEnabled we added inonCreate.
Step 3
Add another instance variable at the top of the class for the help information.
1
privateAlertDialog helpAlert;
We'll use another helper method to show the help information.
The action bar support we've included will only work for API levels of 11 and up, and navigation support will only work for API levels of 16 and up. To support older versions, you'll need to use the support libraries for the action bar and navigation.
Conclusion
Our Hangman game should now be complete. Run it and give it a spin. The application in its current form will only work on recent versions of Android and the user interface is only suited for a limited range of devices. As you can see, there is room for improvement. In addition to supporting a wider ranger of devices, you could enhance the game by adding difficulty levels or word categories. You could even create a leaderboard to keep track of scores.
If you've completed this series successfully, you should have learned about several aspects of the Android platform, including user interaction, adapters, XML resources, and leveraging the action bar.
Nowadays most successful mobile applications are published on multiple platforms. There is a strong tendency to try to design application workflows that work, regardless of the platform. But this can be a mistake.
Many applications might find themselves elevated from "just some app I downloaded" to "an essential app I have to have on my device!" simply by making some tweaks to the way users access the application.
By providing different, cleverly conceived entry points to your application, your application might very well be used a lot more and become invaluable to your users.
The basic application entry points are pretty standardized across the different mobile platforms and developers often focus on these. However, there are also platform-specific mechanisms for getting your user to use your application more often, which are, for the most part, fairly straightforward to implement, and often well worth the effort.
In this tutorial, we will provide an overview of common entry points for Android applications. These entry points will focus on ensuring that your application maximizes its utility to the user.
1. What Are Application Entry Points?
In this discussion, we are using the terminology application entry point to mean "a way that your user gets to your application and uses it." Most of these methods result in your application launching and running, but there are also some subtle ways you might encourage the user to use and appreciate your application without even having to launch it.
Why are Entry Points Important?
I don't think it's unreasonable to say that the more a user uses your application, the more successful your application is likely to become. How you benefit from that usage, whether by charging a fee, through in-app purchases, or by showing ads, is beside the point.
What we’re talking about here is making your application so helpful or essential to the user, that they cannot live without it. If they buy a new device, the first thing they do is download your app.
The Android operating system is well designed for applications to integrate deeply with the user’s working environment, while remaining flexible enough so as not to assume the existence of specific applications or services.
The "Share" feature is a good example of this clever design. An application that creates content does not need to write specific code to share that content on Facebook, Twitter, or SnapChat. The application simply tells the operating system "Hey, I've got this to share!" and the operating system checks which applications can handle that request.
Do I Need More Than One Entry Point?
Most applications benefit from having more than one entry point. If your application isn't shown to the user at the right times, you’re missing key opportunities to improve user experience. This is especially important for applications in the utility and lifestyle categories.
Another reason to consider multiple entry points has to do with user sophistication. If you’ve ever spent time watching someone use a mobile device–especially someone who is at least one generation older or younger than you are—then you’ve probably already realized that people use devices differently.
They navigate differently and they have different levels of understanding about the operating system their device is running. Therefore, it makes sense that you’d want to accommodate these different types of users.
The other argument is that the more ways you provide to the user, the more they will use your application, which is a good thing, right?
Of course, different applications have different needs. Not every strategy makes sense for every application, but, generally speaking, when you only rely on the launch method for your application, you’re selling yourself—and your users—short.
Can I Have Too Many Entry Points?
Applications cannot have too many entry points, but you should see to it that all entry points your application uses make sense for your product. You shouldn't show your application as an option for launch if it doesn't do anything useful for the user.
What you don’t want is for your application to be a nuisance. So it makes no sense, for example, for most music apps to support displaying text documents, or for a game to enable video playback.
You want to get your application launched and used by your user as much as possible. An indispensable application is a successful one. Don’t concern yourself about confusing the user by providing too many entry points. Because of the way the Android operating system is designed, your application will simply be available at the user’s fingertips exactly when they need it, and remain silently in the background when it isn't needed.
2. Examples
In this section, we present a list of some of the most common ways to get your user to be interacting with your Android application. This list is by no means comprehensive and new methods are invented on an almost daily basis. But, in broad strokes, here are some of the most effective methods to lure users in and get them addicted to your application.
Method 1: Your App's Default Launch Sequence
Just about every mobile user understands the default app launch scenario: the user navigates to the app list, taps your app's icon, and launches it. Done!
It doesn’t matter what platform we're talking about. Tapping an app's icon and having the app launch is well understood by most users. Because it's a way your application will most certainly be used, make sure you spend time getting this right. Focus on streamlining the launch process, making it as fast and responsive as possible, while minimizing the taps necessary for the user to get down to business.
The big benefit of the default launch method is that just about every user knows how it works. The drawback, of course, is that the user has to remember to do this on their own.
Try this little exercise: grab your device and go look through all the apps you’ve installed. How many did you download, maybe ran once or twice, and then forget about entirely? Do you feel like launching them now or are they just wasting space on your device?
Most applications work this way. Games especially tend to use this method—launch, start or resume game, play game, save and close game.
Method 2: The Notify & Launch Sequence
A simple way to get users to "remember" to come back to your app is to use notifications. The Android notification system allows for rich notifications to be delivered to the user. The user can read the notification and, if inclined, launch the application.
A good rule of thumb is to provide the richest, most relevant content in notifications. Notification frequency is also very important. You’ve got to strike a balance between reminding users enough to keep them from forgetting about your application, but also not so much that you're spamming or misusing the notification system.
There are a number of best practices for notifications and certain no-nos like badgering your users with marketing notifications, for example.
An email client, for example, may notify the user every time a new mail arrives, but stack and collapse those notifications as needed. For example, if I leave my phone unattended for the day, I may receive 55 new emails, but by the time I look at my notifications, there should only be one notification indicating I have 55 new emails instead of 55 notifications I need to go through one by one.
Note that these notifications are rich: they often contain information about the sender and the subject line and even the first few sentences of the message. They do not just say "You have a new email."
If your application is less a utility and more the stand-alone type, like a game, then you can still use notifications to cajole the user back to your application. I have a game I play sometimes, and if I go a few days without playing, they offer me some free in-game stuff. A strategy like this should be used with caution. You need to avoid bothering your user, perhaps by allowing them to turn off these notifications.
Method 3: Launching By Widgets
Android users customize their devices with widgets on their home and lock screens. Creating a widget that complements your application is an excellent way to keep user eyeballs trained on your application.
Different applications will have different widget requirements. Widgets can do more than display data. You can enable them such that your user can interact with them to shortcut frequent tasks, such as updating their social media status or keep apprised of any changes within the application. Widgets can even launch into the full application, if more features are needed.
A weather application, for example, might use a widget to provide up-to-date forecast data for your current location. Be creative about how to use widgets. For example, a photo gallery application might display cute photographs. A game might have a leaderboard widget, which could entice users back when their friends beat their high score. A travel application might include a widget listing the current TSA threat level or approximate security line wait time at the nearest airport.
Method 4: Launching with Seeded Data by Explicit Intent
The default launch sequence is one where the application just launches without any real knowledge of the user's intent within the application. However, you can also configure your application to launch straight into specific features by providing some metadata with the launch.
Such launches can be implicit or explicit. That is to say, you can create requests to launch a specific application and pass it the data, or you can tell the operating system "Hey, I have this piece of data I want to do something with, what apps can handle it?"
Let’s talk first about the explicit method. In this case, you would likely be the owner of the data to start with. For example, a music player application might have an app widget that allows the user to play music from a playlist. However, the user could click on that widget and the full music player could launch and display all playlists—or the content of that playlist. In this case, your widget would want to cause an explicit launch, because you don’t want to leave it up to the operating system as it may offer the user other music players in addition to yours. It’s not a default launch, instead you'd pass in the playlist data for the current playlist showing in the widget and bring the user straight to the playlist editing screen to do their thing.
Similarly, the widget could display the current song being played of that playlist, and if she taps the album icon for the song, your application could explicitly launch into the album listing screen.
Method 5: Launching with Seeded Data by Implicit Intent
Android's real power really starts to show when we start talking implicit intents. In this case, the requesting application does not specify which application should handle a request. Instead, it just describes the request to the operating system, which uses the intent filtering rules to determine which applications are capable of handling the request. This is also how the operating system figures out which applications can handle an attachment from an email or text message.
For example, a user might receive a music file from a friend and wants to play it. It’s unlikely the email application is capable of playing the audio file. Instead, it’s more likely the client uses an implicit intent to get the operating system to show a list of the applications that can play audio files. So it’s pretty obvious that if your application is capable of playing music, you want the operating system to know it so the user can choose your application over other competing apps.
Your application can listen for specific events sent by the operating system and create intent filters to specify what types of activities and what types of data it can work with.
A media application, for example, might specify that it is capable of playing specific music formats like mp3 or wav files. Similarly, a word processing application might be capable of viewing or editing documents, such as doc and txt files.
However, it wouldn’t make a lot of sense for a word processing application to offer to launch when the user is trying to play music, so you would want to configure your application to filter out requests that don't match it’s run criteria.
The intent filtering mechanism on Android is very powerful and flexible. It's one of the more distinctive and unique features of the Android platform and well worth leveraging, even if the application is also available on platforms that don't support implicit intents. This is especially true if your application can handle common types of content, such as text or audio. A music player consumes music. A social media application might consume text, pictures, and videos. You get the idea.
As we mentioned earlier, this is how Android's "Share" feature works. Let's say you're creating a social media application allowing its users to post text messages, photos, video clips, and sound files. The simplest version of this application might support the default launch scenario:
The user launches the application or uses the application's widget.
The user types a message, captures a photo, shoots a video, or records an audio clip.
The user posts the content to the service.
The user closes the application.
This is a reasonable user scenario, and it’s certainly one that any social media app should support, but it’s not terribly exciting. It doesn’t take into consideration all the other apps that the user has running on their device, generating exciting and pertinent content the user might want to share.
With a few simple modifications, you can let the operating system show your application to any application generating content that matters to your service.
Method 6: Enabling Your App as a "Share" Source
We've talked about how to prepare your application to accept data from other applications, but it's also important to consider the inverse situation—enabling the "Share" feature within your own application.
You may initially feel a little wary of allowing users to basically export data from your application to other apps. There may even be applications that try to prevent this. But most applications thrive when they play nicely with the rest of the operating system.
Here’s an example. A graphics application might have features that let you create amazing art. If this application doesn't offer the option to share the user's creations, the user's content is stuck in the application.
When users demand some way to export their artwork, developers not terribly familiar with Android might be tempted to develop their own export functionality. This is rarely necessary. By using implicit intents to share the user's content, that graphics application does not need to know a thing about which applications can handle the share request or if they're installed on the user's device. That's the operating system's responsibility. The graphics application creates a request saying "Hey, I’ve got this bitmap file. Can anyone do something with it?"
Let's say I have a zombie game I love to play and the game let's me make short video clips. So I decide to take a little clip of my zombie beheading spree for my friends and try to share it. In this situation, your social media application can be set up as the volunteer to help the user when they choose to share the content. Your application basically says "Hey, I can share video clips, give it here!"
Configuring your application as a share target can be straightforward or you can get sophisticated by trying to have your application adapt to new media types as they come along. Consider if you can provide helpful new ways to get users to use your application this way. You can get quite clever and innovative with this kind of stuff. For example, if your application is a music store and player, it could accept text data and try to match it with song titles or albums, creating a sort of hyperlink mechanism.
Different applications are going to find that different launch methods are most effective. However, some of these methods require significant development and can complicate your application's code base, so you'll want to weigh the benefits against the drawbacks in terms of code complexity and maintenance.
Another helpful way to determine which ways are working best is to collect usage data in your application. It's easy to add hooks to all your launch mechanisms. It will enable you to see how your application's users use and don't use your application.
Just remember that not using a method doesn’t necessarily mean it’s not a good idea, it just might require some education to get users to realize they can perform certain tasks. This is easily managed with a help screen or user tips and suggestions at the right time.
Conclusion
Use these opportunities to integrate your application more tightly with the Android operating system. The more your users use your application in their daily tasks, the more valuable your application becomes to them. But as applications become more socially aware and content is generated by applications—be it text, images, audio, video clips, or what have you—many app developers are learning to find interesting ways to create and share, or consume this content with their own applications.