Passing data between activities

In this section, we will explore how to pass data from the main activity to a second activity. While were doing this, we'll practice a little bit of math programming. We will try to calculate the GCF (greatest common factor) of two numbers. We will create two activities (MainActivity and Calculate). The MainActivity will do the following

  1. Wait for user input (two numbers), so we'll create 2 plain text view objects
  2. restrict the inputs to only digits, it doesn't make sense to accept alphanumeric inputs
  3. Check if the text fields if they are empty, we only want to proceed if they are properly filled with number
  4. Create an intent and then we'll piggy back on that it so we can get the two inputted numbers to the Calculate activity

The second activity (Calculate) is the workhorse. It will be the one to do the number crunching. Here's a breakdown of its tasks

  1. Get the intent that was passed from MainActivity
  2. Check if there's some data piggy backing on it
  3. If there's data, we will extract it so we can use it for calculation
  4. When the calculation is done, we will display the results in a text view object

About the GCF algorithm

There are quite a few ways on how to calculate gcf, but the most well known is probably Euclid's algorithm. We will implement it this way.

  1. Get the input of two numbers
  2. Find the larger number
  3. Divide the larger number using the smaller number
    1. If the remainder of step no. 3 is zero, then the GCF is the smaller number
    2. On the other hand, if the remainder is not zero, do the following
      1. The larger number is now assigned the value of the smaller number
      2. The smaller number is now assigned the value of remainder
      3. Repeat step no. 3 (until the remainder is zero)

Let's create a new project using the following details:

  • Project name --- GCF
  • Minimum SDK — API Level 23 (Marshmallow)
  • Form factor — Phone and Tablet only
  • Type of Activity — Empty
  • Layout name — activity_main (default)
  • Activity name — MainActivity (default)

This project will have a second activity. On the project tool window, right click on app → Activity → Empty activity. Use the following details for the newly created activity

  • Activity name — Calculate
  • Layout name — activity_calculate (default, when you enter the activity name)

Fig 1.6.2-1 and 1.6.2-2 shows the layout of files for activity_ main _and _activity_calculate.

Fig 1.6.2-1 activity_main layout

Fig 1.6.2-2 activity_calculate layout

Listing 1.6.2-1 activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  tools:context="com.example.ted.gcf.MainActivity">

  <EditText
    android:id="@+id/firstno"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginTop="63dp"
    android:ems="10"
    android:gravity="center_vertical|center_horizontal"       // (1) 
    android:inputType="number"                                // (2)
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    />

  <EditText
    android:id="@+id/secondno"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginTop="28dp"
    android:ems="10"
    android:gravity="center"
    android:inputType="number"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/firstno"/>

  <Button
    android:id="@+id/button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginTop="29dp"
    android:text="calculate"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/secondno"/>
</android.support.constraint.ConstraintLayout>
  1. Set the gravity attribute to center vertical and horintal to center align the text inside
  2. This restricts the input to numbers only

TIP

  1. You can set the gravity attribute of the EditText in the attributes inspector. While the EditText is selected in the design mode editor, click the "View all attributes" button in the inspector, as shown in Fig 1.6.2-3
  2. You can set the input type of the EditText on the attributes inspector by clicking the ellipsis ( ... ) beside "input type". The choices for input types will be visible on a popup (seee Fig 1.6.2-3)

Fig 1.6.2-3 View all attributes in the inspector

Fig 1.6.2-4 input type attribute on the inspector

We can now move on to the layout details of activity_calculate. The UI elements of the second activity is very simple, there is only one TextView element in. The XML file of the activity_calculate is shown in Listing 1.6.2-2

Listing 1.6.2-2 layout file of Calculate activity

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  tools:context="com.example.ted.gcf.Calculate">

  <TextView
    android:id="@+id/textView"
    android:layout_width="176dp"
    android:layout_height="76dp"
    android:layout_marginTop="113dp"
    android:gravity="center"
    android:text="TextView"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    />
</android.support.constraint.ConstraintLayout>

The details on how to set the constraints will be left to you already. We've already seen detailed examples on how to work with the constraint layout. The quickest way to have a decent layout is to do the following:

  1. Drag and position each view object to the approximate location where you want them to show
  2. Use the "pack" and "align" tool in the constraint inspector (see Fig 1.6.2-5)

Fig 1.6.2-5 Constraint inspector

Listing 1.6.2-3 MainActivity.java

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

  private EditText fno;
  private EditText sno;
  private Button btn;

  @Override
  protected void onCreate(Bundle savedInstanceState) { ... } 

  @Override
  protected void onStart() { ... }                          

  public void onClick(View v) { ... } 

}

The listing above shows the skeleton structure of the MainActivity. The variables fno, sno are defined as class members because we will reference them from both the onClick and onCreate methods. The MainActivity is the listener object that's why the onClick method is overridden in the body of the MainActivity.

NOTE

As you begin to write the codes, AS3 might indicate that there are warnings and errors by displaying some bulb icons and squiggly lines. These are most likely because of missing import statements and method (yet) to be overriden. Use the quick fix to solve these warnings and errors — (alt + enter for Windows and Linux | option + enter for macOS)

Listing 1.6.2-4 onCreate method

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    fno = (EditText) findViewById(R.id.firstno);
    sno = (EditText) findViewById(R.id.secondno);
    btn = (Button) findViewById(R.id.button);
    btn.setOnClickListener(this);
  }

These are very typical codes for the onCreate method. Most of our code samples looks almost identical to this.

Listing 1.6.2-5 onClick method

  public void onClick(View v) {

    boolean a = TextUtils.isEmpty(fno.getText());                    // (1)
    boolean b = TextUtils.isEmpty(sno.getText());                     

    if (!a & !b) {                                                   // (2)

      int firstnumber = Integer.parseInt(fno.getText().toString());  // (3)
      int secondnumber = Integer.parseInt(sno.getText().toString()); 

      Intent intent = new Intent(this, Calculate.class);// (4)
      Bundle bundle = new Bundle();                                  // (5)
      bundle.putInt("fno", firstnumber);                             // (6)
      bundle.putInt("sno", secondnumber);
      intent.putExtra("gcfdata", bundle);                            // (7)
      startActivity(intent);                                         // (8)

    }
  }
  1. TextUtils can check if a TextView object doesn't have any text inside it. You can check for an empty text field some other way by extracting the string inside it and checking the length if it's greater than zero, but TextUtils is a more succinct way to do it
  2. Let's make sure that both text fields are not empty. If one of them is empty, all the codes inside this block will simply be side stepped, so no harm no foul. The app will dutifully wait for user input
  3. The getText() method returns an Editable object, which is not compatible with the parseInt method of the Integer class. The toString method should convert the Editable object to a regular String
  4. This line creates an Intent object. The first argument to the Intent constructor is a context object. The intent needs to know from where it is being launched, hence the this keyword, we are launching the intent from ourself (MainActivity). The second argument to the constructor is the target activity that we want to launch
  5. We are going to piggy back some data into the intent object, so we will need a container for this data. A Bundle object is like a dictionary, it stores data in key-value pairs
  6. The Bundle object supports a bunch of put methods that takes care of populating the bundle. The Bundle can store a variety of data, not only integers. If we wanted to put a string into the Bundle, we could say bundle.putString() or bundle.putBoolean if we wanted to store boolean data
  7. After we've populated the Bundle object, we can now piggyback on the Intent object by calling the putExtra method. Similar to Bundle object, the Intent also uses the key-value pair for populating and accessing the extras. In this case, "gcfdata". We need to use the same key later (in the second activity) to retrieve the bundle
  8. This statement will launch the Activity

Listing 1.6.2-6 onStart method

  @Override
  protected void onStart() {
    super.onStart();
    fno.setText("");
    sno.setText("");
  }

The the onStart method of MainActivity maybe called many times over in the life cycle of the application. It will be called for the first time when we launch the application (after onCreate), and subsequently every time another activity grabs the focus and then the user navigates back to MainActivity. Every time that happens, we're simply clearing out the contents of the text fields. Listing 1.6.2-7 shows the full code for MainActivity.

Listing 1.6.2-7 MainActivity

package com.example.ted.gcf;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

  private EditText fno;
  private EditText sno;
  private Button btn;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    fno = (EditText) findViewById(R.id.firstno);
    sno = (EditText) findViewById(R.id.secondno);
    btn = (Button) findViewById(R.id.button);
    btn.setOnClickListener(this);
  }

  @Override
  protected void onStart() {
    super.onStart();
    fno.setText("");
    sno.setText("");
  }

  public void onClick(View v) {

    boolean a = TextUtils.isEmpty(fno.getText());
    boolean b = TextUtils.isEmpty(sno.getText());

    if (!a & !b) {

      int firstnumber = Integer.parseInt(fno.getText().toString());
      int secondnumber = Integer.parseInt(sno.getText().toString());

      Intent intent = new Intent(this, Calculate.class);
      Bundle bundle = new Bundle();
      bundle.putInt("fno", firstnumber);
      bundle.putInt("sno", secondnumber);
      intent.putExtra("gcfdata", bundle);
      startActivity(intent);

    }
  }
}

MainActivity.java is mostly boilerplate code. It only takes care of the input and launching the second activity. The real work of the GCF happens inside the Calculate activity. Let's walk through the codes of Calculate.java.

After MainActivity passes some data using the Intent and Bundle objects, the first few things we should take care of inside the Calculate activity is to extract that bundle data and eventually extract the key-value pairs of data inside the bundle.

    Intent intent = getIntent();                        // (1)
    Bundle bundle = intent.getBundleExtra("gcfdata");   // (2)
  1. This code will be called inside the onCreate method of the Calculate activity, the getIntent statement here will return whatever was the intent object that was used to launch this activity
  2. The getBundleExtra returns the bundle object which we passed to the intent object in MainActivity. Remember that when we inserted the bundle object in MainActivity, we used the key "gcfdata", hence, we need to use the same key here in extracting the bundle

Once we have successfully extracted the bundle, we can get the two integer values that we stashed in it earlier.

int first = bundle.getInt("fno", 1);
int second = bundle.getInt("sno", 1);

The first parameter of the getInt method is simply the key. This has to be the same key that we used in the putInt method (back in MainActivity). The optional second parameter, is simply a default value, in case the key is not found in the bundle. The next steps will be to start calculating the GCF

Listing 1.6.2-8 GCF logic

    int bigno, smallno = 0;
    int rem = 1;

    if (first > second ) {        // (1)
      bigno = first;
      smallno = second;
    }
    else {
      bigno = second;
      smallno = first;
    }

    while ((rem = bigno % smallno) != 0) { // (2)
      bigno = smallno;                
      smallno = rem;
    }
    gcftext.setText(String.format("GCF = %d", smallno)); // (3)
  1. Were trying to find out which is the larger number, a simple if statement and some assignments to bigno and smallno variable should take care of it
  2. There are two things going on in this statement. First, we are dividing bigno with smallno and we are assigning the remainder to the rem variable. Next, this whole expression is being tested if the result is zero, because if it is, we should exit the while loop. It means we have already found the GCF. If it is not equal to zero, change the values of bigno and smallno according to Euclids algorithm
  3. Once we found the GCF, we will set its value as the text of the TextView object

Listing 1.6.2-9 full code for Calculate.java

package com.example.ted.gcf;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;

public class Calculate extends AppCompatActivity {


  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_calculate);

    int bigno, smallno = 0;
    int rem = 1;

    TextView gcftext = (TextView) findViewById(R.id.textView);
    Intent intent = getIntent();
    Bundle bundle = intent.getBundleExtra("gcfdata");


    if ((bundle != null) & !bundle.isEmpty()) {

      int first = bundle.getInt("fno", 1);
      int second = bundle.getInt("sno", 1);


      if (first > second ) {
        bigno = first;
        smallno = second;
      }
      else {
        bigno = second;
        smallno = first;
      }

      while ((rem = bigno % smallno) != 0) {
        bigno = smallno;
        smallno = rem;
      }
      gcftext.setText(String.format("GCF = %d", smallno));
    }

  }
}

results matching ""

    No results matching ""