So Day 2 of Android development is about to commence. I went through the SDK installation and AVD creation in the previous post, and this time around we're looking to get some controls onto our android pages, or Activities, if you will. A basic Android app layout consists of a hierarchy of ViewGroup and View objects. View's would be the buttons and text fields that we see when we load an app, and the ViewGroup would represent containers for said controls. And as you can see, ViewGroup's can contain Views and other ViewGroup's as well.
Let's Add Controls
For this example we'll add a button and an editable text area to our default activity.
All controls in the Android SDK are rendered using XML syntax, very similar to WPF, if you're familiar with it. There is a WYSIWYG editor also built into the Eclipse Android SDK, but more than likely no one ever uses that for anything, just as you don't use it in any other language that I've seen . So we'll be typing our XML controls directly onto our Activities.
First off locate the xml file in your res/layout/ directory. Mine is called main.xml.
When you open the file, it will open in it's graphical interface form. For now we'll be working on it in xml, so click on the xml tab just below the content pane and we should be dropped into the xml version.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<EditText android:id="@+id/edit_message"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:hint="@string/edit_message" />
<Button android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button_send"
android:onClick="sendMessage"></Button>
</LinearLayout>
The first thing you notice is that I wrapped the activity using a LinearLayout ViewGroup with a horizontal orientation. Which means our controls will flow from left to right. The EditText View is declared with a weight of 1 and no width (0dp) which will allow it to fill the row that it's in. The id is set with the following in mind:
android:id
This provides a unique identifier for the view, which you can use to reference the object from your app code, such as to read and manipulate the object (you'll see this in the next lesson).
The at sign (@) is required when you're referring to any resource object from XML. It is followed by the resource type (id in this case), a slash, then the resource name (edit_message).
The plus sign (+) before the resource type is needed only when you're defining a resource ID for the first time. When you compile the app, the SDK tools use the ID name to create a new resource ID in your project's gen/R.java file that refers to the EditText element. Once the resource ID is declared once this way, other references to the ID do not need the plus sign. Using the plus sign is necessary only when specifying a new resource ID and not needed for concrete resources such as strings or layouts. See the sidebox for more information about resource objects.
After that we declare our Button View and set it's text value to a string resource which we declare externally from this file. The button's onclick event is set to "sendMessage" which we'll get to right after we talk about string resources.
String Resources
Whenever you need to add text to your UI you should do so by making it into a string resource. This ensures that all of your app's text is located in one location and it makes language localization less of a hassle. Be default you should have a string resource file created in:
res/values/strings.xml.
If you open it up you should see the following.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">Hello World, HelloWorldActivity!</string>
<string name="app_name">HelloWorld</string>
<string name="edit_message">enter a message</string>
<string name="button_send">send</string>
<string name="title_activity_display_message">DisplayMessageActivity</string>
<string name="hello_world">Hello world!</string>
<string name="action_settings">Settings</string>
<string name="action_search">this is the action search</string>
</resources>
At this point we should have our default activity with a Button and EditText View, with our UI strings declared in a resource file. Next up, let's make that button do something. We saw above that we can specify the onclick event.
Respond To Button Click
When the user clicks on our button, we would like the contents in the EditText View to get sent to another Activity. We add our button event to the Activity class located in the /src directory that was created for our default Activity.
Let's open that up, and we notice that there is already an onCreate function declared there, which we'll leave alone for now. We'll add our SendMessage function just below that.
/** Called when the user clicks the Send button */
public void sendMessage(View view) {
// Do something in response to button
}
Our button click event requires 3 things. It needs to be a public method, it needs to be a void method and not return anything and it needs to take 1 single parameter, and that is the View that is calling the function.
We Must Have An Intent
An Intent is an object that provides runtime binding between separate components (such as two activities). The Intent represents an app’s "intent to do something." You can use intents for a wide variety of tasks, but most often they’re used to start another activity.
Inside of our sendMessage function, let's create a new Intent. I'll say this, along the way you will get plenty of errors stating that these objects are not defined, and so you'll have to keep adding import statements each time that happens.
Intent intent = new Intent(this, DisplayMessageActivity.class);
The constructor used here takes two parameters:
A Context as its first parameter (this is used because the Activity class is a subclass of Context).
The Class of the app component to which the system should deliver the Intent (in this case, the activity that should be started). Note that we haven't created our new Activity just yet, so we'll receive an error message as of now.
An Intent can also carry data over to another Activty, so let's do that now by taking the content of our EditText View and passing it to our new Activity.
Intent intent = new Intent(this, DisplayMessageActivity.class);
EditText editText = (EditText) findViewById(R.id.edit_message);
String message = editText.getText().toString();
intent.putExtra(EXTRA_MESSAGE, message);
In order to grab the data in our EditText View we'll set the View to a local variable and grab it using the findViewById function. We pass in the ID of the View that we want, which we get from the SDK generated R.java file which contains, all of the resources that are defined in the project. R.id.edit_message gets the edit_message from the id types in the R class. Easy right? getText() will return the content of the EditText View. In order to give the Intent the data we make use of the object's putExtra() function. putExtra takes in a name/value pair that will get sent to the Activity being called. Our key will be the EXTRA_MESSAGE constant that we will define in our main Activity class. We'll use this constant in our next Activity in order to grab the data.
public class MainActivity extends Activity{
public final static String EXTRA_MESSAGE = "com.example.myfirstapp.MESSAGE";
...
}
Our final sendMessage function will look like the following.
/** Called when the user clicks the Send button */
public void sendMessage(View view) {
// Do something in response to button
Intent intent = new Intent(this, DisplayMessageActivity.class);
EditText editText = (EditText) findViewById(R.id.edit_message);
String message = editText.getText().toString();
intent.putExtra(EXTRA_MESSAGE, message);
startActivity(intent);
}
Let's Add A Second Activity
Now that we have our strings defined externally and our controls in the ViewGroup, let's add another Activity (page) that will receive whatever text the user enters in the root Activity and display it. Above we saw our Intent take as a parameter the DisplayMessageActivity class, which we will now create.
After we select Android Activity we'll need to select a Blank Activity Activity to create, and then fill out some basic information on it.
You should now have DisplayMessageActivity.java created in your src directory and an onCreate function that resembles the following:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_display_message);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment()).commit();
}
}
Grab The Intent
Every Activity is invoked by an Intent, regardless of how the user navigated there. You can get the Intent that started your activity by calling getIntent() and retrieve the data contained within it.
In the DisplayMessageActivity class’s onCreate() method, get the intent and extract the message delivered by MainActivity:
Intent intent = getIntent();
String message = intent.getStringExtra(MainActivity.EXTRA_MESSAGE);
To show the message on the screen, create a TextView widget and set the text using setText(). Then add the TextView as the root view of the activity’s layout by passing it to setContentView().
You're final onCreate function should resemble the following:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Get the message from the intent
Intent intent = getIntent();
String message = intent.getStringExtra(MainActivity.EXTRA_MESSAGE);
// Create the text view
TextView textView = new TextView(this);
textView.setTextSize(40);
textView.setText(message);
// Set the text view as the activity layout
setContentView(textView);
}
We can now run our application. Our home Activity will have an EditText View and Button, and clicking the button will load our second Activity with the text entered in the previous Activity.