Android Intents: Part 2: Passing data and returning results between activities

In a previous post we said that intents describe that an action to be performed. we saw how to launch phone activities like phone dialer with intents, and how we passed data (The phone number to dial) to the phone activity.
in this activity we're going to see how to use intents to launch several activities within the same application and how to pass data between them.

we will make an application with three activities: each activity has a button that when pressed navigates to the next activity in a round-robin fashion.
this is how each activity looks like:

each button will navigate to the next activity like this:
btn1.setOnClickListener(new OnClickListener() {
   
   public void onClick(View v) {
    // TODO Auto-generated method stub
   Intent intent=new Intent(IntentsDemo2.this,Activity2.class);
   startActivity(intent);
   }
  });

and the same for each button in the other activities.

we create the intent with a constructor that takes two parameters:
  1. Context: a reference to the current activity.
  2. Class: the type of the activity to be launched by the intent. 
Passing Results between Intents:

By default when you launch an activity using an intent you don't have a feedback on the whether the launched activity finished it's work or not.

we can launch an activity as a sub activity of a parent activity. this means that when the sub activity closes it triggers an event handler in the parent

consider the previous example, we want each activity to display the name of the  activity that was displayed before it.

so we launch the intent normally but we use the Intent.putExtra(String Name,String Value) method to pass any extra data needed.

in the first activity we launch the secondactivity like this:
Intent intent=new Intent(IntentsDemo2.this,Activity2.class);
   intent.putExtra("ComingFrom", "Acticity 1");
final int result=1;
   startActivityForResult(intent, result);

we did not use the startActivity method as we did before, instead we used startActivityForResult(Intent intent, int requestCode)
thich takes two parameters:
  1. The intent to start.
  2. Request code: which is an integer identifier that is used as a corelation id to identify which sub activity has finished it's work (will explain later) .
so the above code launches a sub activity and passes it an extra peice of information via Intent.putExtra method.

Receiving Extra data in sub activity
now the sub activity has been started with an intent from the parent with some extra data. to retreive this data in the sub activity we use the getIntent() method.

the getIntent() method returns a reference t the intent tha started the sub activity.
so in the sub activity we can call the method like this:
@Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.main2);
         Intent sender=getIntent();
         String extraData=sender.getExtras().getString("ComingFrom");
}

this retreives the extra data added to the intent in the parent activity.

Handling sub activity results
now suppose that the parent activity wants to know what was the result returned from the sub activity or wants to get some data from the sub activity, this is handled by overriding the onActivityResult method in the parent activity.

now suppose that the sub activity wants to pass a string containg the word "Hello" to the parent activity.
in the sub activity there is a button that when pressed returns to the parent activity.
the button's click event handler can be like this
btn.setOnClickListener(new OnClickListener() {
    
    public void onClick(View v) {
     // TODO Auto-generated method stub
    Intent intent=new Intent();   
    intent.putExtra("ComingFrom", "Hello");
    setResult(RESULT_OK, intent);
    finish();
        }

here we used the intent.putExtra method to pass the extra data.

we also used the setResult(int result,Intent intent) method to set a result code to be sent to the caller parent activity.
the result code often has two predefined values Result_OK or Result_CANCELED. you can define any result value you want.

also we called finish() method that closes the activity and returrns to the caller activity.

when the finish() method is invoked in the sub activity, the onActivityResult callback method is invoked in the caller activity.

so when overriding the onActivityResult method in the caller activity we can get the data passed from the sub activity.

@Override
    public void onActivityResult(int requestCode,int resultCode,Intent data)
    {
     super.onActivityResult(requestCode, resultCode, data);
     
     String extraData=data.getStringExtra("ComingFrom"));
    }

so this was how intents can be used to pass data and return results between several activities within the same applications.
H9GYCEXU8DZF

Reactions: 

Android Intents: part 1

In this post we are going to explore the concept of intents in Android.

Intents are used by an application to interact with the phone's hardware components or other applications, or to start a service or activity with a certain peice of data or to broadcast that an event has occurred.

Using Intents to launch phone activities:
we can use Intents to launch the phone's basic activities such as the phone dialer, the browser or search.

these intents are called implicit intents cause you don't specify the activity you want to launch, rather Android determines the proper activity to launch based on the required action. also when the launched activity finisheds its work, the original activity has no information that the launched activity has finished it's work

in this example we create an intent that performs a phone number dial action. we don not specify that we want the dialer activity to launch, rather we specify that we want to dial a number and Android launches the dialer activity to perform this action

consider this activity: consists of a TextView and a button to dial the number in the text view.

<?xml version="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:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="Enter the phone number"
    />
<EditText
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/txtNumber"
android:inputType="phone"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Dial"
android:id="@+id/btnDial"
/>
</LinearLayout>




When you press the button the phone dialer launches and then you can call the number.
this is done using the following code
btnDial.setOnClickListener(new OnClickListener() {
   
   public void onClick(View v) {
    // TODO Auto-generated method stub
    
Intent dialIntent=new Intent(Intent.ACTION_DIAL,Uri.parse("tel:"+(txtNumber.getText()).toString()));

startActivity(dialIntent);
   }
  });

notice that the dialer has been launched but the user has to press the call button to make a call.



if you want the phone to dial the number autom atically you could have used this intent
Intent.ACTION_CALL
but this requires ading the following permission to the manifest file:
<uses-permission android:name="android.permission.CALL_PHONE">
and that was how to launch the phone activities using intents.
for a list of available phone actions, check this link

Reactions: 

Android Chronometer Timer

In this post we are going to explore the Android Chronometer control.

The chronometer acts as a timer. In this post we are going to create a simple timer using the Chronometer

Let’s start with the interface:
<?xml version="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:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:id="@+id/txt"
    />
    
    <Chronometer 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:id="@+id/chrono"
    />
    
    <Button 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:id="@+id/btnStart"
    android:text="Start"
    android:onClick="onClick"
    />
    
    <Button 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:id="@+id/btnStop"
    android:text="Stop"
    android:onClick="onClick"
    />
    
    <Button 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:id="@+id/btnReset"
    android:text="Reset"
    android:onClick="onClick"
    />
</LinearLayout>





Define instances of the controls
Chronometer chrono;
Button btnStart;
Button btnStop;
TextView txt;
And some variables
long elapsedTime=0;
String currentTime="";
long startTime=SystemClock.elapsedRealtime();
Boolean resume=false;
we put the Boolean flag differentiate between starting the Chronometer for the first time or resuming it after pause.

Getting inside the onCreate method:
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
chrono=(Chronometer)findViewById(R.id.chrono);
btnStart=(Button)findViewById(R.id.btnStart);
btnStop=(Button)findViewById(R.id.btnStop);
btnReset=(Button)findViewById(R.id.btnReset);
txt=(TextView)findViewById(R.id.txt);

Now to handle each button click event
public void onClick(View v) {
  // TODO Auto-generated method stub
  switch(v.getId())
  {
  case R.id.btnStart:
   btnStart.setEnabled(false);
   btnStop.setEnabled(true);
   if(!resume)
   {
    chrono.setBase(SystemClock.elapsedRealtime());
    chrono.start();
   }
   else
   {
    
    chrono.start();
   }
   
   break;
  case R.id.btnStop:
   btnStart.setEnabled(true);
   btnStop.setEnabled(false);
   chrono.stop();
   chrono.setText(currentTime);
   resume=true;
   btnStart.setText("Resume");
   break;
  case R.id.btnReset:
   
   chrono.stop();
   chrono.setText("00:00");
   resume=false;
   btnStop.setEnabled(false);
   break;
  }
 }


The start button:
The start button can be clicked in two scenarios:
  1. Starting the Chronometer for the first time:
    1. We set base of the Chronometer, which is the time in Milliseconds from where the Chronometer starts counting from.
      We set it to SystemClock.elapsedRealtime() Which is the time in Milliseconds since the device boot (equivalent to current time).
    2. then start the Chronometer
  2. Resuming the chronometer count after start:
    here we start the chronometer again to resume counting from the value it had when it was stopped.

The stop button:
The stop button pauses the chronometer. And sets the resume flag to true to indicate that the next click on the start button will resume counting [not starting counting from zero].

The Reset button:
The stop button resets the chronometer so the next click on start button will start counting from zero

The chronometer can implement OnChronometerTickListener interface which requires an implementation of the onChronometerTick method.


The onChronometerTick method handles the Chronometer tick event which occurs every second.

Here’s the implementation of the onChronometerTick method:
chrono.setOnChronometerTickListener(new OnChronometerTickListener()
        {

   public void onChronometerTick(Chronometer arg0) {
    // TODO Auto-generated method stub
    
    if(!resume)
    {
     
     long minutes=((SystemClock.elapsedRealtime()-chrono.getBase())/1000)/60;
     long seconds=((SystemClock.elapsedRealtime()-chrono.getBase())/1000)%60;
     currentTime=minutes+":"+seconds;
     arg0.setText(currentTime);
     elapsedTime=SystemClock.elapsedRealtime();
    }
    else
    {
     
     long minutes=((elapsedTime-chrono.getBase())/1000)/60;
     long seconds=((elapsedTime-chrono.getBase())/1000)%60;
     currentTime=minutes+":"+seconds;
     arg0.setText(currentTime);
     elapsedTime=elapsedTime+1000;
    }
    
    
   }
         
        }
        );

In this method we handle two scenarios:
  1. The chronometer starts for the first time (or from zero):
    The method is invoked every second Here we calculate the difference between the current time(SystemClock.elapsedRealtime) and the time from which the chronometer started counting(chrono.getBase()) and display it.
    Then we store the current time so that when we pause the chronometer we hold the last value of chronometer
    elapsedTime=SystemClock.elapsedRealtime();
  2. The chronometer is resumed after stop:
    Here we calculate the difference between the last value of the chronometer (elaspedTime) and the value from which the chronometer started counting (chrono.getBase())
    Then we increment the value of the elapsedTime by 1000 milliseconds (1 second) so that it is update with each tick.


And that was a simple stopwatch or timer using Android Chronometer Control. Sure you noticed that it is limited to minutes and seconds only. This is because the onTimerTick method is invoked every second so we cannot update the elapsed milliseconds.

You can download the application from here

Reactions: