10 Android Activity Lifecycle Interview Questions and Answers
Prepare for your Android development interview with our guide on mastering the Android Activity Lifecycle, featuring common questions and detailed answers.
Prepare for your Android development interview with our guide on mastering the Android Activity Lifecycle, featuring common questions and detailed answers.
Understanding the Android Activity Lifecycle is crucial for developing robust and efficient Android applications. This lifecycle defines how activities in an app are created, paused, resumed, and destroyed, which directly impacts the user experience and resource management. Mastery of this concept ensures that your applications run smoothly and handle state transitions gracefully, even under varying conditions such as configuration changes or background processes.
This article provides a curated set of interview questions focused on the Android Activity Lifecycle. By reviewing these questions and their detailed answers, you will gain deeper insights into lifecycle management, enabling you to demonstrate your expertise and problem-solving abilities in your upcoming interviews.
The Android Activity lifecycle consists of several methods that dictate the states an Activity goes through from creation to destruction. These methods are:
The typical sequence of these methods is as follows:
If the activity is paused and then resumed, the sequence would be:
If the activity is stopped and then restarted, the sequence would be:
In the Android Activity Lifecycle, onSaveInstanceState()
is called before an activity is destroyed to allow the activity to save its current state. This method is typically used to save transient information about the activity’s UI state, such as user inputs or the current position in a list.
onRestoreInstanceState()
is called after onStart()
when the activity is being re-initialized from a previously saved state. This method is used to restore the state that was saved in onSaveInstanceState()
.
Example:
@Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putString("user_input", editText.getText().toString()); } @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); if (savedInstanceState != null) { String userInput = savedInstanceState.getString("user_input"); editText.setText(userInput); } }
In this example, the state of an EditText field is saved in onSaveInstanceState()
and restored in onRestoreInstanceState()
.
In Android, the onSaveInstanceState()
method is used to save the state of an Activity before it is destroyed, while the onRestoreInstanceState()
method is used to restore the state when the Activity is recreated.
@Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putString("key", "value"); } @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); if (savedInstanceState != null) { String value = savedInstanceState.getString("key"); } }
To handle configuration changes without restarting the Activity, you can override the onConfigurationChanged
method. This method allows you to manage changes in configuration without the need to restart the Activity.
First, declare in your AndroidManifest.xml that your Activity will handle specific configuration changes:
<activity android:name=".YourActivity" android:configChanges="orientation|screenSize"> </activity>
Then, override the onConfigurationChanged
method in your Activity:
import android.content.res.Configuration; import android.os.Bundle; import androidx.appcompat.app.AppCompatActivity; public class YourActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); // Handle the configuration change if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) { // Handle landscape orientation } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) { // Handle portrait orientation } } }
The onPause()
method is called when the activity is partially obscured, and it is a good place to release resources that are not needed while the activity is not in the foreground. Conversely, the onResume()
method is called when the activity comes back to the foreground, making it the appropriate place to re-acquire those resources.
Example:
public class MainActivity extends AppCompatActivity { private MediaPlayer mediaPlayer; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mediaPlayer = MediaPlayer.create(this, R.raw.sample_audio); } @Override protected void onPause() { super.onPause(); if (mediaPlayer != null && mediaPlayer.isPlaying()) { mediaPlayer.pause(); } } @Override protected void onResume() { super.onResume(); if (mediaPlayer != null) { mediaPlayer.start(); } } @Override protected void onDestroy() { super.onDestroy(); if (mediaPlayer != null) { mediaPlayer.release(); mediaPlayer = null; } } }
In this example, a MediaPlayer object is used to play audio. The onPause()
method pauses the audio when the activity is not in the foreground, and the onResume()
method resumes the audio when the activity returns to the foreground. Additionally, the onDestroy()
method ensures that the MediaPlayer is released when the activity is destroyed.
import android.os.AsyncTask; import android.os.Bundle; import androidx.appcompat.app.AppCompatActivity; import android.widget.TextView; public class MainActivity extends AppCompatActivity { private TextView textView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView = findViewById(R.id.textView); // Start the AsyncTask new BackgroundTask().execute(); } private class BackgroundTask extends AsyncTask<Void, Void, String> { @Override protected String doInBackground(Void... voids) { // Perform background operation return "Background Task Completed"; } @Override protected void onPostExecute(String result) { // Update UI with the result textView.setText(result); } } }
The LifecycleObserver
interface in Android is used to observe lifecycle events of components such as Activities and Fragments. By implementing this interface, you can create classes that respond to lifecycle changes, which helps in managing resources like network connections, sensors, or any other components that need to be cleaned up or initialized at specific points in the lifecycle.
Example:
import androidx.lifecycle.Lifecycle; import androidx.lifecycle.LifecycleObserver; import androidx.lifecycle.OnLifecycleEvent; public class MyObserver implements LifecycleObserver { @OnLifecycleEvent(Lifecycle.Event.ON_START) public void onStart() { // Code to execute when the lifecycle owner is in the STARTED state System.out.println("Lifecycle Owner Started"); } @OnLifecycleEvent(Lifecycle.Event.ON_STOP) public void onStop() { // Code to execute when the lifecycle owner is in the STOPPED state System.out.println("Lifecycle Owner Stopped"); } }
To use this observer in an Activity:
import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); MyObserver observer = new MyObserver(); getLifecycle().addObserver(observer); } }
Memory leaks in Android often occur when an Activity holds references to objects that are not properly released when the Activity is destroyed. This can happen due to various reasons, such as static references, background tasks, or improper use of context.
To avoid memory leaks, developers should:
Example:
public class MainActivity extends AppCompatActivity { private static SomeStaticClass staticClassInstance; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Avoid holding a static reference to the Activity staticClassInstance = new SomeStaticClass(this); } @Override protected void onDestroy() { super.onDestroy(); // Unregister any listeners or callbacks staticClassInstance.cleanup(); } } class SomeStaticClass { private WeakReference<Context> contextRef; SomeStaticClass(Context context) { contextRef = new WeakReference<>(context); } void cleanup() { // Clean up resources } }
In Android, retained fragments are used to maintain the state of a fragment across configuration changes. This is achieved by setting the setRetainInstance(true)
method in the fragment. This is particularly useful for retaining data or long-running operations that should not be recreated on configuration changes.
Here is a concise example of how to implement a retained fragment in an Activity:
public class RetainedFragment extends Fragment { // Data object we want to retain private MyDataObject data; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Retain this fragment across configuration changes setRetainInstance(true); } public void setData(MyDataObject data) { this.data = data; } public MyDataObject getData() { return data; } } public class MainActivity extends AppCompatActivity { private RetainedFragment retainedFragment; private static final String TAG_RETAINED_FRAGMENT = "retained_fragment"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); FragmentManager fragmentManager = getSupportFragmentManager(); retainedFragment = (RetainedFragment) fragmentManager.findFragmentByTag(TAG_RETAINED_FRAGMENT); if (retainedFragment == null) { retainedFragment = new RetainedFragment(); fragmentManager.beginTransaction().add(retainedFragment, TAG_RETAINED_FRAGMENT).commit(); } // Use retainedFragment.getData() to retrieve the retained data // Use retainedFragment.setData(data) to set the data to be retained } }
In the context of the Android Activity lifecycle, an Activity can exist in several states, each representing a different level of interaction with the user and system resources. The three primary states are foreground, visible, and background.
1. Foreground State: An Activity is in the foreground state when it is actively interacting with the user. This means the Activity is at the top of the activity stack and has focus. The onResume()
method is called when the Activity enters this state. In this state, the Activity is fully visible and interactive.
2. Visible State: An Activity is in the visible state when it is partially obscured by another Activity or a dialog but is still visible to the user. The onPause()
method is called when the Activity enters this state. Although the Activity is not in the foreground, it is still visible and retains all state information. However, it may not be fully interactive.
3. Background State: An Activity is in the background state when it is completely obscured by another Activity and is no longer visible to the user. The onStop()
method is called when the Activity enters this state. In this state, the Activity is not visible and may be killed by the system if resources are needed elsewhere. The Activity retains its state information, but it is not interacting with the user.