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");
}
}