Algorithms and OOD (CSC 207 2014S) : Readings

Adding Activities: Making Our Apps Do More Things


Review

We've learned quite a bit so far. We know about the basics of android App development. We know about both the xml and the Java part and we know how they can work together. It might seem like we've focused a little bit more on the xml part of the application process, but it's very important to have a solid understanding of how it works so you don't run into problems later on when you should be paying attention to the Java part.

Adding a New Activity

Remember how we talked about each activity of an app having its own class? It's time to make good on the promise to consider additional activities. Percy Shabunkuns is a very interesting baby chameleon, and he deserves more than just "Hey, I'm a chameleon!" popup message, when we want to find out more about him. So out goal is to make that button take us to another screen with a bit more information. This other screen will be another activity class.

To add an activity we click on the package in our src folder and select File > New > Other....

We want our activity to be a simple Blank Activity, so we press Next.

Now we give it a descriptive name, like ShabunkInfoActivity

Finall, we click Finish.

Adding a new activity auto-generates some files. As you might have expected, a layout xml file for the new activity is created, as well as a new String value for the activity's name.

Besides that, the manifest file was updated to say that our app now has two activities instead of one.

Adding to Our New Activity

Our new activity is very similar to our first activity. We can change how it looks and what UI objects it has via its xml layout file, and we can add resources like strings in the strings.xml file in the values folder. We modify it and interact with the same way we did we our main (first) activity.

Our goal is to display some relevant tidbits about Percy's life. A good way to do this is in form of a list. Here's some information about Percy's life that we could include.

  • Name
  • Age
  • Species
  • Occupation
  • Life Goal
  • Favorite Book
  • Personal Blurb

Now we can create a simple Java class, called Info, that creates objects with the fields we defined above, to create Percy-specific data in our activity.

We can use regular Java classes in Android specific activity classes, just as we would normally. We can access all the methods and fields we have permission to (public/protected/private) and use them in any of our activities.

So, we decided to display our info as a list. Luckily for us, Android provides us with a ListView element that we can add to our activity in its layout xml file. The ListView consists of an infinite (or at least as large as memory can handle) numbers of rows. These rows are actually TextViews, so in order to create our ListView, we also need to define a TextView that tells the ListView exactly how each row will look like. To do that we can create a new xml file that will deal with only our row's TextView.

To make a listView in Android, we simply just drag it onto the layout screen We can leave the layout kind to be a RelativeLayout. There's no reason to change it since it only has one element. ListViews are scrollable by default, so we don't have t worry about having too much information that won't fit in the screen.

To define how a single row looks like, we need to create a new xml file that will contain only the information about that row. To keep it simple, we'll make our rows be TextViews. In that case, our ListView will contain multiple, vertically stacked TextViews. To do this, we simply add a new file to our layout folder, we can call it simple_row.

By default, the xml file will have a LinearLayout, like this:

For it to just have TextView, we can replace the whole xml file with something like this:

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:padding="10dp"
    android:id="@+id/rowTextView"
    android:textSize="16sp" >
    
<"TextView>

ListViews in Android get information via an Adapter that we declare in our Activity class. Because our Info object is a cluster of Strings, a good way to proceed here, is to make of nicely formatted Strings, and feed them to the Adapter. Because we're giving the Adapter an Array, we'll use the ArrayAdapter that takes Strings as arguments.

We probably also want to create a new method, for example createList(), where we can do all of the above, without cluttering the onCreate() method.

As you can see there's a pattern to creating and filling a list in Android development. And the steps that we took are as follows:

  • Create a new activity
  • Put the ListView element on your activity via the graphical layout
  • Define how a sinlge row in the ListView looks like
  • Declare a ListView and an ArrayAdapter object
  • Decide what type of objects the ArrayAdapter will take, by putting it between angle brackets, for example Strings
  • Initialize the ListView object, by getting its id number
  • Declare an array of String objects
  • Initialize the ArrayAdapter with our array
  • Set the Adapter for our ListView

Since we decided to put this in a new method, our activity ends up looking similar to this:

package edu.grinnell.CSC207.F2013.shabunk.AboutMe;

import edu.grinnell.CSC207.F2013.maroltso.AboutMaroltso.R;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.view.Menu;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;

public class ShabunkInfoActivity extends Activity {
	private ListView infoList;
	private ArrayAdapter<String> listAdapter;
	private Info shabunk;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) 
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_shabunk_info);
		
		createList();
	} // onCreate(Bundle)
	
	public void createList () 
	{
		// Grab the listView object from the xml
		infoList = (ListView) findViewById (R.id.listView1);
		
		// Create the Info object
		shabunk = new Info("Percy Shabunkins", "11 months", "Brodypodion", 
				"Master of disguise", "De-snake the planet", 
				"Understanding your everchanging identity", 
				"Hi there, my name is Percy and I am a chameleon. My story is a short one, " +
				"but despite that an interesting one. As an egg I was stolen from my parents' " +
				"warm and loving embrace by an evil overlord, Moldemort. I was hatched into a " +
				"world of cruelty, despair, and bald chameleons with no noses. I was forced " +
				"to do my master's bidding, and suffered in silence for many a month. " +
				"My master was not your average chameleon, for he was able to befriend and" +
				"control chameleons' natural enemies - snakes. He swore to exterminate the" +
				"world of all chameleons with noses, so his kind could reign supreme!" +
				"This was when I knew I had to act! Long story short, I now know how to" +
				"kill snakes, and will proceed to do so until there are none left. The end.");
		
		// Create the nicely formatted String
		String[] aboutShabunk = {"Name:\n " + shabunk.name, "Age:\n " + shabunk.age, 
				"Species:\n " + shabunk.species, "Occupation:\n " + shabunk.occupation, 
				"Life Goal:\n " + shabunk.lifeGoal, "Favourite Book:\n " + shabunk.favoriteBook, 
				"Personal Blurb:\n " + shabunk.personalBlurb};
		
		// Fill the ArrayAdapter with our String array
		listAdapter = new ArrayAdapter<String>(this, R.layout.simple_row, aboutShabunk);
		
		// Get the information from the ArrayAdapter into our list
	} // createList

	@Override
	public boolean onCreateOptionsMenu(Menu menu) 
	{
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.shabunk_info, menu);
		return true;
	} // onCreateOptionsMenu(Menu)

	public void toMain(View v) {
		Intent intent = new Intent(this, AboutShabunkActivity.class);
		startActivity(intent);
	} // toMain()
}

Linking Activities

Now we need to link our activities together, so that we can somehow go from our main screen to our list.

To make this connection, we can create a Button in the graphical layout of our main activity class. We position it wherever we want, give it a name, such as "About", and write a method that will take us to the new screen. To connect a Button with a method, we need to add a new qualifier to the Button's xml definition.

We add android:onClick="name_of_method"

Let's say we'll name our method toInfo. We can add the qualifier before we actually write the method, we just have to make sure to keep the names consistent.

Hint: You don't include parentheses in the qualifier, so in our case, our qualifier would look like this: android:onClick="toInfo".

In our main activity, we now create our method. It's time to introduce another pretty important part of Android development - Intents.

Intents are abstract descriptions of operations to be performed. We use them with the startActivity() method, when we want to move between activities.

Another that that should be noted is that whenever you're trying to write a method that is evoked when the user clicks a certain element on te screen, the method will always have at least one parameters - View.

There's many ways an Intent object can be created. For what we want to do, we'll use one of the simpler constructors.

public Intent(Context packageContext, Class<?> cls)

The Context will simply be this, and the Class<?> will be the Activity we want to go to followed by ".class". After that we just need to use startActivity(), and our Button should be able to take us to our desired screen.

public void toInfo(View v) 
{
    Intent intent = new Intent(this, ShabunkInfoActivity.class);
    startActivity(intent);
} // toInfo (View)

Seeing it all come together

This is what the app looks like now, when we compile and run it. Pretty exciting, eh?

Linking back to our main activity

Usually, apps allow you to go back to the main (or home) activity. We could use another button, and create an Intent like we did to go from our home screen to our info screen, but that's not the conventional way.

On top of each android app we have an Action Bar.

It displays the name of the Activity we're currently on, an Icon for our app (currently the default Android logo) and a clickable three-squares button that acts as a dropdown menu from which we can access certain parts of the app.

The conventional way of linking an app's activity to it's home activity, though looks like this:

You can see that there's a new element on the Action Bar, the arrow that points to the left in the left corner. Clicking the arrow, or around it enables us to go back to our main Activity.

To achieve this we need to put this line before everything else in our onCreate() method in the Activity we want to link back to the home screen:

getActionBar().setDisplayHomeAsUpEnabled(true);

and override the Android specific method onOptionsItemSelected() and make use of Intent to let it know what has to happen.

	@Override
	public boolean onOptionsItemSelected (MenuItem item) 
	{
		Intent upIntent = new Intent(this, AboutShabunkActivity.class);
		startActivity(upIntent);
		return true;
	} // onOptionsItemSelected (MenuItem)

Unfortunately, the call getActionBar().setDisplayHomeAsUpEnabled(true); requires us to have a minimum SDK of 11. We've set up our app with a minimum SDK target of 8. This means that the method won't work for machines that use the Android API 10 or below.

Since we don't really have to worry about that, because we're not deploying our app, and there are very few machines that actually run on APIs below 11, there's little harm in changing our minimum SDK requirement. To do this, we go to the AndroidManifest.xml file, and change the minimum SDK version from 8 to 11.

Once that's done, we save the file, and we can run our app. It now links perfectly between two activities.

Copyright (c) 2013-14 Samuel A. Rebelsky.

Creative Commons License

This work is licensed under a Creative Commons Attribution 3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by/3.0/ or send a letter to Creative Commons, 543 Howard Street, 5th Floor, San Francisco, California, 94105, USA.