When an android activity stopped, it may be recycled by the android OS. But how to store recycled activity instance state data, and use those activity instance data later? Android provides the below methods.
1. How To Save / Retrieve Activity Instance State Data.
- Override Activity’s onSaveInstanceState(Bundle outState) method. And save the desired data in the Bundle input parameter with key-value pair.
- The onSaveInstanceState(Bundle outState) method will be invoked before onStop() method.
- Retrieve the saved instance state data in the onCreate(Bundle savedInstanceState) method use the Bundle input parameter also.
- You can also retrieve the saved instance state data in the onRestoreInstanceState(Bundle savedInstanceState) method.
- Please Note: The activity instance state data can only be saved and retrieved between different instances of the same android activity class. Different activity classes can not use this method to share data.
2. Save / Retrieve Activity Instance State Data Example.
2.1 Example Activities.
This example contains two activities.
- ActivityStateActivity: This activity includes an input text box and a button. Users can input email in the input text box. When clicking the button, it will open the below activity.
- ActivityStateTargetActivity : This activity contains a TextView which show some text message.
2.2 Example Execution Steps.
- Click the button in the first activity. The second activity will be displayed. You can see a demo video on URL https://youtu.be/0STgcF6kKyk.
- Click the emulator toolbar to change the screen orientation from vertical to horizontal. This can make the first activity be destroyed and recycled by android OS.
- Click the back menu at the bottom of the emulator.
- You can see the input email still exist.
- But please see the log data in LogCat, when return back, the first activity’s onCreate() method is called again.
Main activity onCreate savedInstanceState is null. Main activity onPause. Main activity onSaveInstanceState. Main activity onStop. Main activity onDestroy. Main activity onCreate savedInstanceState is not null. Main activity onRestoreInstanceState.
- If you do not change the screen orientation from vertical to horizontal. From the log, we can see the first activity’s onRestart() method will be invoked automatically. But this time, the first activity is not destroyed and recycled. It is still the original activity.
Main activity onCreate savedInstanceState is null. Main activity onPause. Main activity onSaveInstanceState. Main activity onStop. Main activity onRestart.
2.3 Main Layout Xml File.
- activity_state.xml
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Email : "/> <EditText android:id="@+id/emailInputBox" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout> <Button android:id="@+id/startAnotherActivityButton" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Start Another Activity"/> </LinearLayout>
2.4 Main Activity Java File.
- ActivityStateActivity.java
package com.dev2qa.example; import android.content.Intent; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; public class ActivityStateActivity extends AppCompatActivity { // Log tag name. private final static String LOG_TAG_UI = "LOG_TAG_UI"; // Bundle state key. private final static String USER_INPUTTED_EMAIL = "USER_INPUTTED_EMAIL"; // Email input text box. private EditText emailInputBoxEditText = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_state); emailInputBoxEditText = (EditText)findViewById(R.id.emailInputBox); if(savedInstanceState!=null) { Log.d(LOG_TAG_UI, "Main activity onCreate savedInstanceState is not null."); // Retrieve activity instance state data. String email = savedInstanceState.getString(USER_INPUTTED_EMAIL); // Set the original email data in EditText view component. emailInputBoxEditText.setText(email); }else { Log.d(LOG_TAG_UI, "Main activity onCreate savedInstanceState is null."); } setTitle("dev2qa.com - Activity State Example"); // Click this button to display second activity. Button startAnotherActivityButton = (Button)findViewById(R.id.startAnotherActivityButton); startAnotherActivityButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(ActivityStateActivity.this, ActivityStateTargetActivity.class); startActivity(intent); } }); } @Override protected void onRestart() { super.onRestart(); Log.d(LOG_TAG_UI, "Main activity onRestart."); } @Override protected void onPause() { super.onPause(); Log.d(LOG_TAG_UI, "Main activity onPause."); } @Override protected void onStop() { super.onStop(); Log.d(LOG_TAG_UI, "Main activity onStop."); } @Override protected void onDestroy() { super.onDestroy(); Log.d(LOG_TAG_UI, "Main activity onDestroy."); } // This method will be invoked before onStop() method. @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); String email = emailInputBoxEditText.getText().toString(); outState.putString(USER_INPUTTED_EMAIL, email); Log.d(LOG_TAG_UI, "Main activity onSaveInstanceState."); } @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); String email = savedInstanceState.getString(USER_INPUTTED_EMAIL); Log.d(LOG_TAG_UI, "Main activity onRestoreInstanceState."); } }
2.5 Target Activity Layout Xml File.
This XML file also includes another button. Click this button will finish and destroy all activities in this task stack.
- activity_state_target.xml
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="This is the target activity." android:textSize="20dp"/> <Button android:id="@+id/destroyPreviousActivityButton" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Destroy Previous Activity"/> </LinearLayout>
2.6 Target Activity Java File.
- ActivityStateTargetActivity.java
package com.dev2qa.example; import android.app.ActivityManager; import android.content.ComponentName; import android.content.Context; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.widget.Button; import com.dev2qa.example.constant.LogTagName; import java.util.List; public class ActivityStateTargetActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_state_target); setTitle("dev2qa.com - Target Activity."); // Click this button will destroy and recycle all activities. Button destroyPreviousActivityButton = (Button)findViewById(R.id.destroyPreviousActivityButton); destroyPreviousActivityButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Context context = getApplicationContext(); // Get activity manager. ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); // Get AppTask list. List<ActivityManager.AppTask> appTaskList = activityManager.getAppTasks(); if(appTaskList!=null) { // Loop the list, destroy and recycle all activity in this activity stack. int appTaskListSize = appTaskList.size(); for(int i = 0;i<appTaskListSize;i++) { ActivityManager.AppTask appTask = appTaskList.get(i); ActivityManager.RecentTaskInfo recentTaskInfo = appTask.getTaskInfo(); ComponentName componentName = recentTaskInfo.baseActivity; String baseActivityClassName = componentName.getClassName(); Log.d(LogTagName.LOG_TAG_UI, baseActivityClassName); if("com.dev2qa.example.ActivityStateActivity".equals(baseActivityClassName)) { appTask.finishAndRemoveTask(); } } } } }); } }