Always On, Always Connected Week 2 - Android Development Basics

Logging

Add the following import statement to your code:
import android.util.Log;
And within the onClick method add a line like this:
Log.v("Clicker", "Button Clicked");
To see the log messages, we need to tell Eclipse to show them to us. Their is a panel in Eclipse (part of the Android integration) called LogCat. To open LogCat, select Window: Show View: Other: Android: LogCat



You should see a new panel open at the bottom of your Eclipse Workspace called "LogCat". Now when you run the application, you can use the "LogCat" pane to view what is happening.

Logging Screencast


Download it: Logging.mp4.mp4

Making Toast

As proof that Android has a sense of humor there is a class called Toast which allows us to pop-up messages. Let's make our onClick method in Hello World pop-up some toast.

We'll need to import android.widget.Toast along with the rest of our import statements. Following that we can just use it. We use the static method "makeText" to create a new Toast view and then the "show" method to display it.
Toast t = Toast.makeText(this,"Button Clicked!",Toast.LENGTH_LONG);
t.show();
Here is our full source code:
package com.mobvcasting.helloworld;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

public class HelloWorld extends Activity {
	
	Button aButton;
	
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        aButton = (Button) this.findViewById(R.id.Button01);
        aButton.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				aButton.setText("You Clicked Me");
		    	
				Toast t = Toast.makeText(this,"Button Clicked!",Toast.LENGTH_LONG);
    				t.show();

			}});        
    }
}


Toast Screencast


Download it: Toast.mp4.mp4

Activity

As we spoke about previously, an Activity is a class that represents something in between a single screen and a full application. In a model, view, controller world, an Activity would be a controller, providing the application logic.

Activity Life Cycle

Up until now, we have only been dealing with the onCreate lifecycle method in our Activities
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
The onCreate method is run once when the Activity is first created. This means that we can't count on the method being run everytime the application is brought to the front. For instance, if we have a Button that updates the contents of a TextView, the updated value may still be there next time the Application is run by the user.
Here is an example:
package com.mobvcasting.activitylifecycle;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class ActivityLifecycle extends Activity implements OnClickListener {

	Button aButton;
	TextView aTextView;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
	
		aButton = (Button) this.findViewById(R.id.Button01);
		aTextView = (TextView) this.findViewById(R.id.TextView01);

		aButton.setOnClickListener(this);
	 }


	 public void onClick(View view) {
		  if (view == aButton) {
			   aTextView.setText("Button was pressed!");
		  }
	 }
}
And the layout XML file: main.xml
<?xmlversion="1.0"encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
    <TextView 
         android:id="@+id/TextView01"
         android:layout_width="fill_parent" 
         android:layout_height="wrap_content" 
         android:text="Starting State"
    />
    <Button 
         android:id="@+id/Button01"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:text="Press Me"
    />
</LinearLayout>
Running this the first time, the TextView will display "Starting State" as specified in the layout XML. After pushing the button, it will change to "Button was pressed!". Leaving the app (by pushing the home button or by some other means) and then coming back, the text will most likely still read "Button was pressed!".
This is because Android by default doesn't quit the application when the user leaves. It continues running in the background and it's state may be retained as shown in this example.
We can force the Activity to quit by calling the finish() method. We can do this in one of the methods that is called when the Activity is left.
public void onPause() {
     super.onPause();
     finish();
}
The onPause() method is called when the Activity is no longer in front. It is guaranteed to be called whereas the onStop() method may not be called if Android decides to destroy the Activity before it is called (after onPause()).
As with all of the lifecycle methods, the corresponding method in the super class needs to be called first thing.
Forcing the Activity to finish() onPause probably isn't the best form and it goes against the way Android is supposed to work. To simply make something happen every time an Activity is brought to the front we can use the onResume() or the onStart() methods.
public void onResume() {
     aTextView.setText("Starting State");
}
Here is a diagram from the Android SDK documentation that illustrates the Activity Lifecycle methods that may be called: http://developer.android.com/images/activity_lifecycle.png

Activity Lifecycle Demonstration Part 1


Download It: ActivityLifecycle_1.mp4.mp4

Activity Lifecycle Demonstration Part 2


Download It: ActivityLifecycle_2.mp4.mp4

Multiple Activities

Let's create a second Activity in our existing project and have it load the other.xml layout:
package com.mobvcasting.multiplescreens;

import android.app.Activity;
import android.os.Bundle;

public class OtherActivity extends Activity {

     @Override
     public void onCreate(Bundle savedInstanceState) { 
          super.onCreate(savedInstanceState); 
          setContentView(R.layout.other);
     }
}

AndroidManifest.xml Adding Activities

Before we go any further, we have to tell the Android system about our new Activity by adding an entry for it in the AndroidManifest.xml file for our project.
The line we need to add is as follows:
        
It should appear within the tag but not inside the existing tag.
Here is my full AndroidManifest.xml file for this project:
<?xmlversion="1.0"encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.mobvcasting.multiplescreens"
      android:versionCode="1"
      android:versionName="1.0">
    <application android:icon="@drawable/icon"android:label="@string/app_name">
        <activity android:name=".MultipleScreens"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        <activityandroid:name=".OtherActivity"></activity>
    </application>
    <uses-sdkandroid:minSdkVersion="5"/>
</manifest> 

Intents

Now we can modify the our first Activity to launch this second Activity when the button is pressed. To do this we use something called an Intent.
An Intent is another building block of Android applications. It essentially boils down to telling the OS to launch something or perform some action and give us the ability to pass a message or other data along.
Within an application, we use intents to launch other activities:
Intent i = new Intent(this, OtherActivity.class); 
startActivity(i);
Our full first Activity will look like this:
package com.mobvcasting.multiplescreens;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class MultipleScreens extends Activity implements OnClickListener {

     Button changeButton;
     TextView textView;

     LayoutInflater inflater;

     View mainView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        inflater = LayoutInflater.from(this);
        mainView = inflater.inflate(R.layout.main, null);
        
        changeButton = (Button) mainView.findViewById(R.id.MainButton);
        changeButton.setOnClickListener(this);
        
        textView = (TextView) mainView.findViewById(R.id.MainTextView);

        setContentView(mainView);        
    }

     public void onClick(View v) {
          Intent i = new Intent(this, OtherActivity.class); 
          startActivity(i);
     }
}
Now when we push the button on the first screen, the first activity is stopped (or paused) and the other activity is launched. One side effect here is that we can use the "back" button to go back to the first Activity.
If we add a button to our other activity and call finish(), we'll return to our first activity.
The button in other.xml:
    <Button 
         android:id="@+id/OtherButton"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:text="Press Me to finish"
    />
Calling finish when the button is pressed:
package com.mobvcasting.multiplescreens;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class OtherActivity extends Activity implements OnClickListener {

     Button finishButton;

     @Override
     public void onCreate(Bundle savedInstanceState) { 
          super.onCreate(savedInstanceState); 
          setContentView(R.layout.other);

          finishButton = (Button) this.findViewById(R.id.OtherButton);
          finishButton.setOnClickListener(this);
     }

     public void onClick(View v) {
          finish();
     }
}

Multiple Activities Screencast


Download It: MultipleActivities.mp4.mp4