Sans Pareil Technologies, Inc.

Key To Your Business

Lab 2: Activity Lifecycle, Events and Testing

Activity Lifecycle

We will enhance the application we developed earlier and observe Activity lifecycle by adding logging statements to the main callback methods. 

  • Copy the GridSample application directory to a new directory and name it Lab2
  • Open the Lab2 directory in Android Studio
  • Edit the MainActivity class
  • Use the IDE to override methods from the parent Activity class.  
    • Override the onResume, onSaveInstaneState, onRestoreInstanceState, onRestart, onPause, onStop and onDestroy methods.
    • Log the method names in your implementation
  • Run the application and observe the logging patterns (remove the logging statements from the NumberAdapter class if you wish)
  • Edit MainActivity class.  We will now store a random number to a Bundle in the save state call back method, and retrieve the same value back in the on restore state call back method.
    • Introduce a final SecureRandom field in the class.
    • Seed the SecureRandom instance with System.currentTimeMillis() in onCreate.
    • Put a new int value in the outState Bundle parameter in onSaveInstanceState with key "random" and the nextInt value from the SecureRandom instance.
    • Modify the log statement in onRestoreInstanceState to also print out the value of the "random" key in the savedInstanceState Bundle parameter.
  • Run the application.  Change the device orientation in the emulator using CTRL+F11 and observe the logs

Event Handling

We will add an even listener to the cell's displayed in the GridView.  To illustrate that we have handled the click/touch event, we will display a Toast message that just displays the text displayed in the selected cell.

  • Edit the NumberAdapter class and add an OnClickListener to the TextViews created in getView
    • Create an inner class ClickListener that implements OnClickListener
    • Let the IDE generate the method defined in the interface
    • In the method implementation create and show a Toast message that displays the text in the clicked TextView.
  • Introduce and initialize a private final field in NumberAdapter of type ClickListener.
  • Edit the getView method
    • Set the clickable property of the TextView instance in getView to true (this enabled click handling).
    • Set the OnClickListener for the TextView instance to the ClickListener instance.
  • Run the application and test click event handling.

Application Testing

We will now develop and automated test suite that will test the application and event handling logic we have implemented.  We will use the Espresso framework throughout our Lab sessions to automatically test the features we add to our application.

Configure Android Studio to run unit tests

  • Launch the "Project Settings" dialog
    • Select the "app" module
    • In the "Flavors" tab, specify android.support.test.runner.AndroidJUnitRunner for the Test Instrumentation Runner property.
    • Click "OK" and close the dialog
  • Edit the "Gradle Scripts"->build.gradle (Module: app) file.
    • Add androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.1' under dependencies { ... }
  • Create a new test class named MainActivityTest
    • Add the following annotations before the class declaration: (LargeTest indicates that the test needs an emulator/device to run).
      @RunWith( AndroidJUnit4.class )
      @LargeTest
    • Add a JUnit rule as follows:
      @Rule  public final ActivityTestRule<MainActivity> activityTestRule = new ActivityTestRule<>( MainActivity.class );
    • Add a JUnit test method which tests the cell at position 4 into our data model as follows.  Use the IDE to static import the methods invoked. Note that we need to use onData to select View items that are rendered dynamically (Adapter based views).
      @Test
      public void cell()
      {
        final int index = 4;
        onData( anything() )
            .inAdapterView( withId( R.id.gridView ) ).atPosition( index )
            .check( matches( withText( format( "Cell %d", index ) ) ) );
      }
    • Add another test method that tests all cells as follows:
      @Test
      public void allCells()
      {
        final GridView gridView = (GridView) activityTestRule.getActivity().findViewById( R.id.gridView );

        for ( int i = 0; i < gridView.getAdapter().getCount(); ++i )
        {
          onData( anything() )
              .inAdapterView( withId( R.id.gridView ) ).atPosition( i )
              .check( matches( withText( format( "Cell %d", i ) ) ) );
        }
      }
    • Add a test method that tests click handling for a grid cell as follows.  Note that since a Toast message is not part of the main window for the activity, it cannot be tested directly as we would test other View instances.
      @Test
      public void onClick()
      {
        final int index = 4;
        onData( anything() )
            .inAdapterView( withId( R.id.gridView ) ).atPosition( index )
            .perform( click() );

        onView( withText( format( "Cell %d", index ) ) )
            .inRoot( withDecorView( not( activityTestRule.getActivity().getWindow().getDecorView() ) ) )
            .check( matches( isDisplayed() ) )
            .check( matches( withText( format( "Cell %d", index ) ) ) );
      }
    • Click the "Build Variants" tab in Android Studio and make sure Test Artifact is set to "Android Instrumentation Tests".
    • Right-click the MainActivityTest file in the IDE and choose the "Run MainActivityTest" menu item to run the test case.
    • Experiment with different text in the methods to see how failures are reported.
    • Introduce a 5 second sleep between the onData and onView invocations in onClick and observe the result.