Android code is organized in such a way that code for an application's logic and its user interface are segregated. This is by design. It practically begs us to decrease coupling and increase cohesion in our application code...principles we try to attain when writing "good" Object Oriented programs. Developing an app in this manner makes it possible to apply changes to the GUI and the program logic independently, making it easier to debug, update, and maintain.
Because it's assumed that you already know how to program in Java, you should already have an understanding of how to create the program logic. It's no different than writing any other Java program. In order to ensure proper cohesion, each Class should have a well-defined role, having methods directly related to the desired functionality of the class. What we're going to talk about today is the other part of the equation, the user interface.
** If you get stuck doing something outlined below, you should go back and review what you did in the Hello World lesson **
All Android GUI elements are subclasses of the View object. User interfaces are composed of a combination of Views. A View is a Java Class that inherits directly from the Java Object class, the root of the Java class hierarchy. Views are the basic building block for all Android GUI elements, and serve as the base class for all GUI widgets. Links to each View subclass shown in the hierarchy above can be found at the bottom of this page (quick link).
(src: http://developer.android.com/images/viewgroup.png)
A ViewGroup is a special subclass of the View class that serves as a container for multiple Views. There are several useful widgets that extend the ViewGroup Class. Most are actually subclasses of another ViewGroup known as a Layout.
Layouts are a special type of ViewGroup that serve as the framework for organizing an app's multiple Views on the device's screen. There are several Layout types, each having its own properties and/or parameters. We'll talk about Layouts in more detail in another lesson. For now, if you want more information on common layouts, read this: Common Layouts
For this course, do not use the Graphical Layout editor! In order to actually learn the code and gain a better understanding of exactly what's going on, you must edit the XML file directly.
In order to become more familiar with how Views are created, let's take a closer look at a couple of the more common GUI elements.
Once the project is created, open the layout file that was created for you (res > layout > content_main.xml by default) and look at the TextView element (in XML...not in the Graphical Layout!).
As a reminder, in XML there are two methods for defining an element's opening and closing tags:
<element></element>
<element />
We see both of these methods in use in our layout file: the RelativeLayout element uses method 1, and the TextView element uses method 2.
A user interface is composed of several Views nested inside a Layout element. All of a View's properties are defined inside the start tag. They are called Attributes. At a minimum, a View must have the layout_width and layout_height attribute values assigned.
To get a bit of practice with manipulating Views in XML, do the following:
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
Have a a look at the display preview to see the results of your hard labor (Hint: there's a little line to the right of the text):
Not too impressive :-/
To explain, by default Linear Layouts arrange their contents on the screen horizontally, from left to right. By changing the orientation attribute of the layout to vertical, the contents will be arranged on the screen from top to bottom. This attribute is only applicable to Linear Layouts. Had it remained a Relative Layout, the process to place the EditText below the TextView would be much different!
Let's take a minute to see our work in action:
Click the Return/Enter button on the keyboard. You see that the cursor moves to a new line (as you would expect). You can change this by adding this attribute to an EditText or TextView:
android:singleLine="true"
Have you ever noticed that in some apps there are times when a different keyboard is presented (for example, when entering an email address or phone number)? That is because the developer has specified a value for the inputType attribute. By default, an EditText has an inputType value of text. It also provides a great example of how the attributes in your layout file have a direct affect on the user experience.
I'll assume you figured out how to let the IDE tell you the available options. For a full description of input types, go here: http://developer.android.com/reference/android/widget/TextView.html#attr_android:inputType
We now have two of the most common Views under our belts. In order to demonstrate how your app can respond to user action, let's add some functionality. We'll need to add another of the most common View types: a Button.
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Click Me" />
There are many more Views that we could examine (and we will in a later lesson), but I think you get the point for now. Each View type has attributes unique to it, but all are created in the same manner as above. When you get a chance, I highly recommend that you take the time to familiarize yourself with all of the Views provided to you in the SDK.
Of course, since Android is completely open source, and since you know how to extend classes in Object-Oriented code, if you ever get to the point that you need something that just doesn't exist, you can create your own View!
Here are your tasks. If you've paid attention over that last few lessons, you should be able to knock this out in no time:
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// your code here
}
});
Once you're finished, feel free to compare your results against my sample solution at the bottom of the page.
Here's a semi-complete, hierarchical listing of some of the most used Views:
For a more complete listing of View options, methods and parameters, look here: http://developer.android.com/reference/android/view/View.html
In order to complete the tasks above, you'll need to modify three files: content_main.xml, strings.xml and MainActivity.java.
Task 1: Change the Button text attribute so that it references a string resource instead of being hard-coded
To accomplish this, you need to create a new string resource in the res > values > strings.xml file:
<string name="button_text">Click Me!</string>
Once you've created the string resource, modify your content_main.xml so that the Button's text attribute points to the new resource:
android:text="@string/button_text"
Task 2: Add button click functionality
So that we can reference them in our java code, define id attributes in the TextView, EditText , and Button views in content_main.xml:
android:id="@+id/myViewName"
Then, write the logic code in MainActivity.java. There are a couple of ways to accomplish this:
Option 1: This is probably the one you did. Create Java class objects for each of our views, set an OnClickListener to the Button, and instantiate a new OnClickListener...all in the onCreate() method of MainActivity.java, like so:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView textview1 = (TextView) findViewById(R.id.textView1);
final EditText edittext1 = (EditText) findViewById(R.id.editText1);
Button button1 = (Button) findViewById(R.id.button1);
button1.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
textview1.setText(edittext1.getText());
edittext1.setText("");
}
});
}
Option 2: This is what I did. I'll explain the benefits in a minute. First, have a look at the code:
public class MainActivity extends Activity implements OnClickListener {
TextView textview1;
EditText edittext1;
Button button1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textview1 = (TextView) findViewById(R.id.textView1);
edittext1 = (EditText) findViewById(R.id.editText1);
button1 = (Button) findViewById(R.id.button1);
button1.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if(v == button1){
textview1.setText(edittext1.getText());
edittext1.setText("");
}
}
}
There are two major differences between the two options given:
textview1.setOnClickListener(this);
Then modify onClick() so that it reacts differently depending on whether the Button or the TextView was clicked:
public void onClick(View v) {
if(v == button1){
textview1.setText(edittext1.getText());
edittext1.setText("");
} else if(v == textview1){
// do something else
}
}
Notice that when checking to see which View was clicked, I compared the View argument to the class variables I defined above.