package com.example.android.lifecycle; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.widget.TextView; import java.util.ArrayList; public class MainActivity extends AppCompatActivity { /* * This tag will be used for logging. It is best practice to use the class's name using * getSimpleName as that will greatly help to identify the location from which your logs are * being posted. */ private static final String TAG = MainActivity.class.getSimpleName(); /* * This constant String will be used to store the content of the TextView used to display the * list of callbacks. The reason we are storing the contents of the TextView is so that you can * see the entire set of callbacks as they are called. */ private static final String LIFECYCLE_CALLBACKS_TEXT_KEY = "callbacks"; /* Constant values for the names of each respective lifecycle callback */ private static final String ON_CREATE = "onCreate"; private static final String ON_START = "onStart"; private static final String ON_RESUME = "onResume"; private static final String ON_PAUSE = "onPause"; private static final String ON_STOP = "onStop"; private static final String ON_RESTART = "onRestart"; private static final String ON_DESTROY = "onDestroy"; private static final String ON_SAVE_INSTANCE_STATE = "onSaveInstanceState"; /* * This TextView will contain a running log of every lifecycle callback method called from this * Activity. This TextView can be reset to its default state by clicking the Button labeled * "Reset Log" */ private TextView mLifecycleDisplay; // COMPLETED (1) Declare and instantiate a static ArrayList of Strings called mLifecycleCallbacks /* * This ArrayList will keep track of lifecycle callbacks that occur after we are able to save * them. Since, as we've observed, the contents of the TextView are saved in onSaveInstanceState * BEFORE onStop and onDestroy are called, we must track when onStop and onDestroy are called, * and then update the UI in onStart when the Activity is back on the screen. */ private static final ArrayList<String> mLifecycleCallbacks = new ArrayList<>(); /** * Called when the activity is first created. This is where you should do all of your normal * static set up: create views, bind data to lists, etc. * * Always followed by onStart(). * * @param savedInstanceState The Activity's previously frozen state, if there was one. */ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mLifecycleDisplay = (TextView) findViewById(R.id.tv_lifecycle_events_display); /* * If savedInstanceState is not null, that means our Activity is not being started for the * first time. Even if the savedInstanceState is not null, it is smart to check if the * bundle contains the key we are looking for. In our case, the key we are looking for maps * to the contents of the TextView that displays our list of callbacks. If the bundle * contains that key, we set the contents of the TextView accordingly. */ if (savedInstanceState != null) { if (savedInstanceState.containsKey(LIFECYCLE_CALLBACKS_TEXT_KEY)) { String allPreviousLifecycleCallbacks = savedInstanceState .getString(LIFECYCLE_CALLBACKS_TEXT_KEY); mLifecycleDisplay.setText(allPreviousLifecycleCallbacks); } } // COMPLETED (4) Iterate backwards through mLifecycleCallbacks, appending each String and a newline to mLifecycleDisplay /* * Since any updates to the UI we make after onSaveInstanceState (onStop, onDestroy, etc), * we use an ArrayList to track if these lifecycle events had occurred. If any of them have * occurred, we append their respective name to the TextView. * * The reason we iterate starting from the back of the ArrayList and ending in the front * is that the most recent callbacks are inserted into the front of the ArrayList, so * naturally the older callbacks are stored further back. We could have used a Queue to do * this, but Java has strange API names for the Queue interface that we thought might be * more confusing than this ArrayList solution. */ for (int i = mLifecycleCallbacks.size() - 1; i >= 0; i--) { mLifecycleDisplay.append(mLifecycleCallbacks.get(i) + "\n"); } // COMPLETED (5) Clear mLifecycleCallbacks after iterating through it /* * Once we've appended each callback from the ArrayList to the TextView, we need to clean * the ArrayList so we don't get duplicate entries in the TextView. */ mLifecycleCallbacks.clear(); logAndAppend(ON_CREATE); } /** * Called when the activity is becoming visible to the user. * * Followed by onResume() if the activity comes to the foreground, or onStop() if it becomes * hidden. */ @Override protected void onStart() { super.onStart(); logAndAppend(ON_START); } /** * Called when the activity will start interacting with the user. At this point your activity * is at the top of the activity stack, with user input going to it. * * Always followed by onPause(). */ @Override protected void onResume() { super.onResume(); logAndAppend(ON_RESUME); } /** * Called when the system is about to start resuming a previous activity. This is typically * used to commit unsaved changes to persistent data, stop animations and other things that may * be consuming CPU, etc. Implementations of this method must be very quick because the next * activity will not be resumed until this method returns. * * Followed by either onResume() if the activity returns back to the front, or onStop() if it * becomes invisible to the user. */ @Override protected void onPause() { super.onPause(); logAndAppend(ON_PAUSE); } /** * Called when the activity is no longer visible to the user, because another activity has been * resumed and is covering this one. This may happen either because a new activity is being * started, an existing one is being brought in front of this one, or this one is being * destroyed. * * Followed by either onRestart() if this activity is coming back to interact with the user, or * onDestroy() if this activity is going away. */ @Override protected void onStop() { super.onStop(); // COMPLETED (2) Add the ON_STOP String to the front of mLifecycleCallbacks /* * Since any updates to the UI we make after onSaveInstanceState (onStop, onDestroy, etc), * we use an ArrayList to track if these lifecycle events had occurred. If any of them have * occurred, we append their respective name to the TextView. */ mLifecycleCallbacks.add(0, ON_STOP); logAndAppend(ON_STOP); } /** * Called after your activity has been stopped, prior to it being started again. * * Always followed by onStart() */ @Override protected void onRestart() { super.onRestart(); logAndAppend(ON_RESTART); } /** * The final call you receive before your activity is destroyed. This can happen either because * the activity is finishing (someone called finish() on it, or because the system is * temporarily destroying this instance of the activity to save space. You can distinguish * between these two scenarios with the isFinishing() method. */ @Override protected void onDestroy() { super.onDestroy(); // COMPLETED (3) Add the ON_DESTROY String to the front of mLifecycleCallbacks /* * Since any updates to the UI we make after onSaveInstanceState (onStop, onDestroy, etc), * we use an ArrayList to track if these lifecycle events had occurred. If any of them have * occurred, we append their respective name to the TextView. */ mLifecycleCallbacks.add(0, ON_DESTROY); logAndAppend(ON_DESTROY); } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); logAndAppend(ON_SAVE_INSTANCE_STATE); String lifecycleDisplayTextViewContents = mLifecycleDisplay.getText().toString(); outState.putString(LIFECYCLE_CALLBACKS_TEXT_KEY, lifecycleDisplayTextViewContents); } /** * Logs to the console and appends the lifecycle method name to the TextView so that you can * view the series of method callbacks that are called both from the app and from within * Android Studio's Logcat. * * @param lifecycleEvent The name of the event to be logged. */ private void logAndAppend(String lifecycleEvent) { Log.d(TAG, "Lifecycle Event: " + lifecycleEvent); mLifecycleDisplay.append(lifecycleEvent + "\n"); } /** * This method resets the contents of the TextView to its default text of "Lifecycle callbacks" * * @param view The View that was clicked. In this case, it is the Button from our layout. */ public void resetLifecycleDisplay(View view) { mLifecycleDisplay.setText("Lifecycle callbacks:\n"); } }