본문으로 건너뛰기

Activity Lifecycle Examples

Understanding the Activity Lifecycle in Android.

Android is a mobile operating system that is widely used in smartphones and tablets. As an android developer, it is essential to know how to manage the lifecycle of an activity. The lifecycle of an activity is a series of states that an activity goes through from the time it is created to the time it is destroyed. In this article, we will discuss the different states of the activity lifecycle and how to manage it.

Activity States

An android activity can be in one of four states at any given time. These states are:

  1. Active or Running State: This is the state where the activity is currently visible to the user and actively running.

  2. Paused State: This is the state where the activity is partially visible to the user but is not currently in focus. For example, when a dialog box appears above the activity, the activity is in the paused state.

  3. Stopped State: This is the state where the activity is not visible to the user, but its state is still in memory. This can happen when the user navigates to another app or when the activity is no longer needed.

  4. Destroyed State: This is the state where the activity is completely removed from memory and is no longer available.

Activity Lifecycle Methods

An activity has several lifecycle methods that are called at different stages of its lifecycle. These methods are:

  1. onCreate(): This method is called when the activity is first created. This is where you can initialize any variables or data structures that your activity needs.

  2. onStart(): This method is called when the activity becomes visible to the user. At this point, the activity is in the foreground, and the user can interact with it.

  3. onResume(): This method is called when the activity is in the foreground and has focus. This is where you can start animations or other background tasks that require user interaction.

  4. onPause(): This method is called when the activity is partially visible to the user, but is not in focus. This is where you should stop any animations or other background tasks.

  5. onStop(): This method is called when the activity is no longer visible to the user. This is where you should release any resources that your activity is holding on to.

  6. onRestart(): This method is called when the activity is stopped and then started again. This can happen when the user navigates back to the activity.

  7. onDestroy(): This method is called when the activity is destroyed. This is where you should release any resources that your activity is holding on to.

Managing the Activity Lifecycle

It is essential to manage the activity lifecycle to ensure that your application runs smoothly and efficiently. Here are some tips on how to manage the activity lifecycle:

  1. Save and restore state: When an activity is stopped or destroyed, it is important to save its state so that it can be restored when it is started again. You can do this by implementing the onSaveInstanceState() and onRestoreInstanceState() methods.

  2. Release resources: When an activity is stopped or destroyed, it is important to release any resources that it is holding on to. For example, if your activity is playing media, you should stop it and release the resources when the activity is stopped.

  3. Use Fragments: Fragments are a way to modularize your application and manage the lifecycle of each module independently. By using fragments, you can ensure that your application runs smoothly even if the user navigates away from the activity.

Code Examples

Here is an example of how to implement the lifecycle methods in Kotlin:

class MainActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Initialize any variables or data structures here
}

override fun onStart() {
super.onStart()
// Your code here
}

override fun onResume() {
super.onResume()
// Your code here
}

override fun onPause() {
super.onPause()
// Your code here
}

override fun onStop() {
super.onStop()
// Release any resources here
}

override fun onRestart() {
super.onRestart()
// Your code here
}

override fun onDestroy() {
super.onDestroy()
// Release any resources here
}

override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
// Save state here
}

override fun onRestoreInstanceState(savedInstanceState: Bundle) {
super.onRestoreInstanceState(savedInstanceState)
// Restore state here
}
}

And here is an example in Java:

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Initialize any variables or data structures here
}

@Override
protected void onStart() {
super.onStart();
// Your code here
}

@Override
protected void onResume() {
super.onResume();
// Your code here
}

@Override
protected void onPause() {
super.onPause();
// Your code here
}

@Override
protected void onStop() {
super.onStop();
// Release any resources here
}

@Override
protected void onRestart() {
super.onRestart();
// Your code here
}

@Override
protected void onDestroy() {
super.onDestroy();
// Release any resources here
}

@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// Save state here
}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
// Restore state here
}
}

More

Activities are a fundamental and component of android development. An activity encapsulates a screen that the user interacts with. Activities will typically contain components which user shall interact with. These can be buttons, lists, edittexts etc. The activity however has it's own lifecycle and you can listen to the events emitted by the activity through lifecycle methods.

What is Activity Lifecycle?

Your app's Activity instances experience different stages of their lifecycle as users navigate through, out of, and back into it. An activity can be told when its state has changed through a number of callback methods: when the system is creating, stopping, resuming, or destroying its process.

When a user leaves and re-enters an activity, you can declare what to do within the lifecycle callback methods. Therefore, each callback allows specific actions to be taken in response to changes in state. Performing the right work at the right time and properly handling transitions will improve the performance and robustness of your application. You can avoid the following issues if you properly implement the lifecycle callbacks:

  • A crash that occurs when a user receives a phone call or switches to another app.
  • Utilization of considerable system resources even without the user's active involvement.
  • In cases where the user leaves and returns to your app later, and find they lost their previous app state. For example if they were typing some data, they find that they have to restart typing again.
  • A crash or loss of progress experienced when the screen is rotated between landscape and portrait..

In this tutorial we learn these lifecycle methods practically by writing code that does something when such an event is raised.

(a). Create an App that Lists Activity Lifecycle Methods in Kotlin

In this example you will learn basic interaction with these methods. We show a simple toast message when such an event is raised.

We use android studio and kotlin

Step 1: Dependencies

No dependencies are needed for this project.

Step 2: Kotlin Code

Start by creating a file named MaiActivity.kt.

MainActivity.kt

Then add imports:

import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*
import java.lang.StringBuilder

Then extend the AppCompatActivity:

class MainActivity : AppCompatActivity() {

The first lifecycle method we override is the onCreate(). This is raised when the activity is first created. We will inflate our xml layout here. The append some text to our textbuilder. Then show the text in a textview.

    override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
sb.append("\n onCreate Called")
tv.text = sb.toString()
Log.d("ACTIVITY_LIFECYCLE", "onCreate Called")
}

We then override our onStart(). This is raised when the activity is started and becomes visible for use:


override fun onStart() {
super.onStart()
sb.append("\n onStart Called")
tv.text = sb.toString()
Log.d("ACTIVITY_LIFECYCLE", "onStart Called")
}

And so on and so forth.

Here's the full code:

package info.camposha.activitylifecycle

import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*
import java.lang.StringBuilder

class MainActivity : AppCompatActivity() {
val sb: StringBuilder = StringBuilder()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
sb.append("\n onCreate Called")
tv.text = sb.toString()
Log.d("ACTIVITY_LIFECYCLE", "onCreate Called")
}

override fun onStart() {
super.onStart()
sb.append("\n onStart Called")
tv.text = sb.toString()
Log.d("ACTIVITY_LIFECYCLE", "onStart Called")
}

override fun onResume() {
super.onResume()
sb.append("\n onResume Called")
tv.text = sb.toString()
Log.d("ACTIVITY_LIFECYCLE", "onResume Called")
}

override fun onPause() {
super.onPause()
sb.append("\n onPause Called")
tv.text = sb.toString()
Log.d("ACTIVITY_LIFECYCLE", "onPause Called")
}

override fun onStop() {
super.onStop()
sb.append("\n onStop Called")
tv.text = sb.toString()
Log.d("ACTIVITY_LIFECYCLE", "onStop Called")
}

override fun onDestroy() {
super.onDestroy()
sb.append("\n onDestroy Called")
tv.text = sb.toString()
Log.d("ACTIVITY_LIFECYCLE", "onDestroy Called")
}
}

Step 3: Layouts

activity_main.xml

The main thing about our main activity layout is that we will have a textview that will be showing the lifecycle methods as they are raised:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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=".MainActivity">

<TextView
android:id="@+id/tv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text=""
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

Step 4: Run

Run the project and you will get the following:

Example 2: Kotlin Android Activity Lifecycle

This is a Kotlin Activity lifecycle method. We log out the called lifecycle callback using a Logger.

Step 1: Create Project

Start by creating an empty Android Studio project.

Step 2: Dependencies

We are writing the example in Kotlin thus we will add the kotlin dependency:

    implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"

We will also add the typical appcompat and constraint layout:

    implementation "androidx.appcompat:appcompat:$buildToolsVer"
implementation "androidx.constraintlayout:constraintlayout:$constraintLayoutVersion"

Those are our only dependencies.

Step 3: Design Layout

In this case we will have a simple TextView in our layout:

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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.developers.activitylifecycle.MainActivity">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

Step 4: Write Code

Go to your MainActivity.kt file and add the following imports:

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import java.util.logging.Logger

Extend the MainActivity:

class MainActivity : AppCompatActivity() {

Create a companion object and define a log inside it. This will log out our lifecycle methods:


companion object {
val log = Logger.getLogger(MainActivity::class.java.name)
}

Override the onCreate() and log out the onCreate message:

    override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
log.info("OnCreate Called")
}

Override the onStart(), onRestart(), onResume(), onPause(), onStop() and onDestroy() and log out the appropriate message:

    override fun onStart() {
super.onStart()
log.info("onStart Called")
}

override fun onRestart() {
super.onRestart()
log.info("OnRestart Called")
}

override fun onResume() {
super.onResume()
log.info("OnResume Called")
}

override fun onStop() {
super.onStop()
log.info("OnStop Called")
}

override fun onPause() {
super.onPause()
log.info("OnPause Called")
}

override fun onDestroy() {
super.onDestroy()
log.info("OnDestroy Called")
}

}

Here is the full code:

MainActivity.kt

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import java.util.logging.Logger

class MainActivity : AppCompatActivity() {

companion object {
val log = Logger.getLogger(MainActivity::class.java.name)
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
log.info("OnCreate Called")
}

override fun onStart() {
super.onStart()
log.info("onStart Called")
}

override fun onRestart() {
super.onRestart()
log.info("OnRestart Called")
}

override fun onResume() {
super.onResume()
log.info("OnResume Called")
}

override fun onStop() {
super.onStop()
log.info("OnStop Called")
}

override fun onPause() {
super.onPause()
log.info("OnPause Called")
}

override fun onDestroy() {
super.onDestroy()
log.info("OnDestroy Called")
}

}

Run

Copy the code or download it in the link below, build and run.

Reference

Here are the reference links:

NumberLink
1.Download Example
2.Follow code author
3.Code: Apache 2.0 License

Example 3: Kotlin Android Activity Lifecycle Example

Here is another example of Activity Lifecycle using Kotlin in Android. We log and show Toast messages for each method.

Step 1: Create Project

Start by creating an empty Android Studio project.

Step 2: Dependencies

No third party dependencies are needed.

Step 3: Override Methods

You can override the Activity lifecycle methods as follows:

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.Toast

class MainActivity : AppCompatActivity() {

var TAG = "Event"

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

Log.d(TAG, "onCreate")
Toast.makeText(this,"onCreate",Toast.LENGTH_SHORT).show()
}

override fun onRestart() {
super.onRestart()
Log.d(TAG, "onRestart")
Toast.makeText(this,"onRestart",Toast.LENGTH_SHORT).show()
}

override fun onStart() {
super.onStart()
Log.d(TAG, "onStart")
Toast.makeText(this,"onStart",Toast.LENGTH_SHORT).show()
}

override fun onResume() {
super.onResume()
Log.d(TAG, "onResume")
Toast.makeText(this, "onResume", Toast.LENGTH_SHORT).show()
}

override fun onPause() {
super.onPause()
Log.d(TAG, "onPause")
Toast.makeText(this, "onPause", Toast.LENGTH_SHORT).show()
}

override fun onStop() {
super.onStop()
Log.d(TAG, "onStop")
Toast.makeText(this, "onStop", Toast.LENGTH_SHORT).show()
}

override fun onDestroy() {
super.onDestroy()
Log.d(TAG, "onDestroy")
Toast.makeText(this, "onDestroy", Toast.LENGTH_SHORT).show()
}

}

Run

Copy the code or download it in the link below, build and run.

Reference

Here are the reference links:

NumberLink
1.Download Example
2.Follow code author

Screen Configuration Change

In this piece we look at android solutions related to configuration changes in the android device.

Here's a simple note about handling configuration changes according to android official documentation:

Some device configurations can change during runtime (such as screen orientation, keyboard availability, and when the user enables multi-window mode). When such a change occurs, Android restarts the running Activity ( onDestroy() is called, followed by onCreate()). The restart behavior is designed to help your application adapt to new configurations by automatically reloading your application with alternative resources that match the new device configuration.

To properly handle a restart, it is important that your activity restores its previous state. You can use a combination of onSaveInstanceState(), ViewModel objects, and persistent storage to save and restore the UI state of your activity across configuration changes. Read more about it here.

How do you listen to configuration changes in android?

Step 1 - Specify configChanges property in android manifest

Like this:

<activity android:name=".MyActivity"
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
android:label="@string/app_name">

The code declares an activity that handles both screen orientation changes and keyboard availability change.

  • The "orientation" value prevents restarts when the screen orientation changes.
  • The "screenSize" value also prevents restarts when orientation changes, but only for Android 3.2 (API level 13) and above.
  • The "screenLayout" value is necessary to detect changes that can be triggered by devices such as foldable phones and convertible Chromebooks.
  • The "keyboardHidden" value prevents restarts when the keyboard availability changes.

Step 2: Override onConfigurationChanged method

Like this:

@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);

int newOrientation = newConfig.orientation;

if (newOrientation == Configuration.ORIENTATION_LANDSCAPE) {
// show("Landscape");
} else if (newOrientation == Configuration.ORIENTATION_PORTRAIT){
// show("Portrait");
}
}

Or you can use a switch statement:

int orientation=newConfig.orientation;

switch(orientation) {

case Configuration.ORIENTATION_LANDSCAPE:

//to do something
break;

case Configuration.ORIENTATION_PORTRAIT:

//to do something
break;

}

In Kotlin:

override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)

// Checks the orientation of the screen
if (newConfig.orientation === Configuration.ORIENTATION_LANDSCAPE) {
Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show()
} else if (newConfig.orientation === Configuration.ORIENTATION_PORTRAIT) {
Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show()
}
}

Note that after before writing your implementation code you need to add super.onConfigurationChanged(newConfig); or else an exception may be raised.

Observations

The onConfigurationCalled() may not be called if you

1.Set layout to landscape in XML

android:screenOrientation="landscape"

2. Invoke setRequestedOrientation manually

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

3. You have both "android:screenOrientation" and "android:configChanges" specified.

Example - How to Handle Screen Orientation changes

Let's create a simple example that will observer configuration changes in an android activity and show a toast message based on whether the screen is rotated portrait or landscape.

Step 1- Create Layout

Add the following code in your xml layout:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />

</RelativeLayout>

Step 2: MainActivity.java

Then add the following code in your main activity:

package com.example.screenorientation;

import android.os.Bundle;
import android.app.Activity;
import android.content.res.Configuration;
import android.view.Menu;
import android.widget.Toast;

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
onConfigurationChanged(new Configuration());
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
// TODO Auto-generated method stub
super.onConfigurationChanged(newConfig);

if(getResources().getConfiguration().orientation==Configuration.ORIENTATION_PORTRAIT)
{
Toast.makeText(getApplicationContext(), "portrait", Toast.LENGTH_SHORT).show();
System.out.println("portrait");
}
else if (getResources().getConfiguration().orientation==Configuration.ORIENTATION_LANDSCAPE) {
Toast.makeText(getApplicationContext(), "landscape", Toast.LENGTH_SHORT).show();
System.out.println("landscape");
}
else
{
Toast.makeText(getApplicationContext(), "none", Toast.LENGTH_SHORT).show();
System.out.println("none");
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}

}

Conclusion

Managing the activity lifecycle is essential to ensure that your application runs smoothly and efficiently. By following the tips and examples provided in this article, you can ensure that your application is well-designed and user-friendly. Remember to save and restore state, release resources, and use fragments to modularize your application.

That's it.