Android Activity Lifecycle Explained: Enhance Your App's Navigation

Android Activity Lifecycle Explained: Enhance Your App's Navigation

Explore expert techniques to enhance Android app navigation using Activity Lifecycle insights.

Activity

Single UI-Screen present to the user.

Different events, some user-triggered and some system-triggered can cause an Activity to transition from one state to another.

As a user navigates through the application, the Activity instances in our app transition through different states in their lifecycle. The Activity class provides several callbacks that let the activity know when a state changes or that the system is creating, stopping, or resuming an activity or destroying the process the activity resides in.

Within the lifecycle callback methods, we can declare how the activity behaves during such state transition.

The Activity class provides us with a set of six callback methods, which are invoked by the activity based on the state transition of the activity:

  1. onCreate()

    • activity is created.

    • this is where we create views, bind data to lists, instantiate class-scope variables & call the setContentView() method to define the activities layouts.

    • receives the parameter savedInstanceState, which is a Bundle object containing the activity's previously saved state. If the activity has never existed before, the value of the object is null.

    • passes to onStart()

        override fun onCreate(savedInstanceState: Bundle?) { 
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
        }//Eg - Music App UI Created
      
  2. onStart()

    • activity becomes visible to the user.

        override fun onStart(){
            super.onStart()
        }//Eg - Music App UI Visible to User
      
  3. onResume()

    • invoked just before the activity starts interacting with the user

    • activity comes at the top of the activity stack

    • and implements most of the app's functionality

      •             override fun onResume(){
                        super.onResume()
                    }//Invoked after onStart()
        
  4. onPause()

    • invoked when activity loses focus & enters a paused state

    • activity remains partially visible

    • passes to onStop() or onResume() methods depending on the transition

        override fun onPause(){
            super.onPause()
        }//Eg - Call Received
        //Invokes onResume when call declined
      
  5. onStop()

    • invoked when activity is no longer visible to the user

    • passes to onDestroy() or onRestart() method

    • onRestart() method is invoked when an activity in a stopped state is about to restart & it restores the state of the activity. Followed by onStart() .

        override fun onStop(){
            super.onStop()
        }//Eg - Invoked when call accepted 
        //moves to onRestart() when call ends
      
  6. onDestroy()

    • invoked when activity is destroyed.

        override fun onDestroy(){
            super.onDestroy()
        }//Invoked when application closed
      

Demonstration of an Activities Lifecycle

As we run our Application :

  1. The onCreate(), onStart(), onResume() method for the main activity are invoked in order.

  2. When the button to go to the second activity is pressed:

    the onPause() method for main activity is invoked

    the onCreate(), onStart(), onResume() method for the second activity are invoked in order.

    the onStop() method for main activity is invoked

  3. When the button to go to the main activity is pressed:

    the onPause() method for the second activity is invoked

    the onCreate(), onStart(), onResume() method for the main activity are invoked in order.

    the onStop() method for the second activity is invoked

    When the Orientation of the main activity is changed or a Multi-Window mode is enabled by the user:

    the onPause(), onStop(), onDestroy(), onCreate(), onStart(), onResume() method for the main activity are invoked in order, and the new instance of the activity is created

    However as the activity is re-created, the data inputted in the main activity is lost . Hence, considering data-saving and implementing callback methods properly is a must. Data may also be lost when our MainActivity is destroyed from the back stack by the OS to free some space.

Creation of Activity Switching :

val countText : TextView = findViewById(R.id.countText) 
val incrementBtn : Button = findViewById(R.id.incrementBtn)
val changeBtn : Button = findViewById(R.id.changeBtn)
//helps us handle the textView & our button in the MainActivity.kt

incrementBtn.setOnClickListener{    
//lambda function in the Button class enabled when button clicked
    countText.text = "${countText.text.toString().toInt()} + 1" 
//increment text   
}

changeBtn.setOnClickListener{
    val intent = Intent(this, SecondActivity::class.java)
    startActivity(intent)
    //starts an intent that switches context to SecondActivity.kt
}

Coming Back to our MainActivity, after incrementing the countText value to a certain value and then heading to the SecondActivity.

However changing the orientation of our device leads to loss of data as the MainActivity is recreated.

Dealing with data loss :

  1. Using the onSaveInstanceState() method, which is a lifecycle method in Android used to save temporary state data of an activity before it is destroyed. The saved state is stored in a Bundle object, which can later be retrieved to restore the data when the activity is recreated.
  • Save the data using the onSaveInstanceState(Bundle) method.

  • Retrieve the saved data using the onCreate(Bundle) method or the onRestoreInstanceState(Bundle) method.

// Restore data if available
if (savedInstanceState != null)    count = savedInstanceState.getInt("count", 0)
countText.text = count.toString()

incrementBtn.setOnClickListener {
    count++
    countText.text = count.toString()
}

// Save data before activity is destroyed
// called before onStop() or onPause(), if the activity is getting destroyed
override fun onSaveInstanceState(outState: Bundle) {
    super.onSaveInstanceState(outState)
    outState.putInt("count", count)
}
  1. Using ViewModel class from Android Jetpack which helps retain data across configuration changes without relying on lifecycle methods.

  2. Using Persistent Storage for data that needs to persist beyond app restarts or user sessions, eg: database, or a file, etc.

Tasks & Backstack

A task is a collection of activities that the user does.
These activities are arranged in a stack called the back stack in the order in which each activity is opened, which operates as a last-in-first-out data structure.

Hence, when the user taps back, the activities are popped from the back stack.

In the above example, when the user presses the app icon on the device, a new task is created, and the following application's main activity is put in the back stack.
Opening further activities on the application leads them too on the back stack, however as the user navigates on the back button, the topmost activity is popped off.