This is the sixth day of my participation in the August More text Challenge. For details, see:August is more challenging

This chapter describes the Activity lifecycle, state, and methods that the system calls when the state switches.

  • A Nonexistent expression indicates that the activity is not existent or visible, is not in memory, or has been destroyed, and has no associated view for the user to view or interact with. (Happens when the back leg button is clicked)
  • Stopped means that the activity has an instance in memory, but its view is not visible on the screen. (Occurs when you start another full-screen activity or click the home button on your phone)
  • Paused indicates that the activity does not interact with the user in the foreground but is visible or partially visible to the view. (Like a dialog box pops up)
  • The Resumed indicates an activity that is fully visible and in the foreground in the memory. At any given time, only one activity in the entire system can be in the resumed state. This means that if an activity enters a resumed state, another activity may drop out of the resumed state.

The Activity class provides a number of callbacks that let the Activity know that a state has changed.

In general, by overriding the onCreate(Bundle) method, an activity can preprocess the following UI-related work:

  • Instantiate components and place them on the screen (call the setContentView(int) method);
  • Referencing an instantiated component;
  • Set up listeners for the component to handle user interactions;
  • Access external model data.

Log tracing understands the activity lifecycle

The android.util.Log class from the previous chapter prints logs by adding the Log TAG definition above mainActivity.kt, and then, Print logs in the onCreate(), onStart(), onResume(), onPause(), onStop(), and onDestroy() lifecycle callbacks, respectively.

private const val TAG = "MainActivity"

class MainActivity : AppCompatActivity() {
      ...
      override fun onStart() {
        super.onStart()
        Log.d(TAG, "onStart() called")
    }
    ...
}
Copy the code

Start app log:

Click the Home button to log:

Re-enter the APP log:

Rotate app log:

Exit app log:

Device configuration and Activity lifecycle

Rotating the device changes the device configuration. Device configuration refers to the screen direction, screen pixel density, screen size, keyboard type, and language.

When runtime configuration changes occur, there may be more appropriate resources to match the new device configuration. Android then destroys the current activity, finds the best resources for the new configuration, and creates new instances to use those resources. In demo, create a layout directory and add -land, res/layout-land. The result is that when the device is horizontal, Android will find and use the layout resources in the res/layout-land directory.

Android configuration modifier list and equipment configuration information website: developer.android.com/guide/topic…

UI update and multi-window mode

Before Android 7.0, it was common to use onResume() and onPause() to start or stop any uI-related updates in progress (animation and data refresh). After Android 7.0, there is multi-window mode, and the activitiy that has been suspended is also visible. We want activitiy that has been suspended to behave like normal activities. For example, if you’re watching a video, you can move resuming and pausing to onStart() and onStop(), and that’ll do the job.

Revisit the Activity lifecycle

This method is usually called by the system before the onStop() method, unless the user presses the back key. The activity is then completely erased from memory, so there is no need to save data for reconstruction. A Bundle is a structure that stores a mapping (key-value pairs) between a string key and a value of a restricted type.

So, you can solve the rotation problem by overriding the onSaveInstanceState(Bundle) method, saving some data in the Bundle, and then fetching the data in the onCreate(Bundle) method.

Note that data types stored and restored in the Bundle can only be primitive types and objects that implement either Serializable or Parcelable interfaces. It is not a good idea to save custom class objects in the Bundle because the objects you fetch may no longer be used. It is better to save custom class objects in other ways, while keeping the basic type data that identifies the object in the Bundle.

In-depth study: Activity memory cleaning status

In the low memory state, Android directly clears the entire application process from memory, including all the activities of the application. Currently, Android doesn’t have the ability to destroy a single activity.

Here’s how to enable Don’t Keep Activities using the developer Settings on your Android phone

When the back button is clicked, the system always destroys the current activity, telling the system that “the user no longer needs the current activity.”

Learn more about logging levels and methods

Of course, the print Log is also a level, usually the error Log is used log.e, the default is red, it is very conspicuous, but some information, it is best not to hit this level, it affects the elimination of errors.

On log print: www.jianshu.com/p/de79bbf35…

Challenge exercise: no more than one answer

  1. Boolean array that defines whether the question has been answered
private var mQuestionsAnswered: BooleanArray? = BooleanArray(questionBank.size)
Copy the code
  1. Write a method to set the state of the answer button
private fun setBtnEnabled(enabled: Boolean) {
        trueButton.isEnabled = enabled
        falseButton.isEnabled = enabled
    }
Copy the code
  1. Each time the answer is checked, immediately set the answer button status to false and the current value of the Boolean array of whether the question was answered to true, so add two lines of code to the checkAnswer method
private fun checkAnswer(userAnswer: Boolean) { ... setBtnEnabled(false) mQuestionsAnswered? .set(currentIndex, true) }Copy the code
  1. Each page turn updates the button status as to whether the current question has been answered, so add code to the updateQuestion() method
private fun updateQuestion() { ... setBtnEnabled(! mQuestionsAnswered? .get(currentIndex)!!) }Copy the code
  1. To solve the rotation problem, we need to keep the array of answers, define a KEY, and store the array in onSaveInstanceState()
private const val KEY_QUESTION_ANSWERED = "answered"

override fun onSaveInstanceState(savedInstanceState: Bundle) {
        ...
        savedInstanceState.putBooleanArray(KEY_QUESTION_ANSWERED, mQuestionsAnswered)
}
Copy the code
  1. Finally, of course, in the onCreate method, we need to get the array that just saved to answer the question, and solve the problem of rotating the initialization value
if (savedInstanceState ! = null) { currentIndex = savedInstanceState.getInt(KEY_INDEX, 0) mQuestionsAnswered = savedInstanceState.getBooleanArray(KEY_QUESTION_ANSWERED) }Copy the code

Challenge exercise: Rating (after the user answers all the questions, a TOAST message is displayed, giving the rating in percentage form)

  1. Define an Int number of correct answers, initialized to 0
 private var mTrueAnswerCount = 0
Copy the code
  1. Every time you click the answer button, when you check the answer, to check that it’s correct, you put the mTrueAnswerCount ++
private fun checkAnswer(userAnswer: Boolean) { val correctAnswer = questionBank[currentIndex].answer val messageResId = if (userAnswer == correctAnswer) { mTrueAnswerCount++ R.string.correct_toast } else { R.string.incorrect_toast } Toast.makeText(this, messageResId, Toast.LENGTH_SHORT).show() setBtnEnabled(false) mQuestionsAnswered? .set(currentIndex, true) getScoreResult() }Copy the code
  1. Write a method to get the score, always thinking, when the answer will be finished, because you can skip the answer, just answer all the prompts, so MY processing is at the end of the checkAnswer () method, will call the method to get the score, In the getScoreResult() method, you can determine whether you have completed all the questions. If you do not do anything, you can calculate the percentage of the current score that pops up
private fun getScoreResult() { var isAllAnswered = true for (i in questionBank.indices) { if (! mQuestionsAnswered? .get(i)!!) { isAllAnswered = false return } } if (isAllAnswered) { Toast.makeText( this, "${mTrueAnswerCount * 100 / questionBank.size} %", Toast.LENGTH_LONG ).show() } }Copy the code
  1. The last rotation question, of course, defines a key that holds the number of questions currently answered correctly
private const val KEY_TRUE_ANSWER_COUNT = "true_answer_count"

mTrueAnswerCount = savedInstanceState.getInt(KEY_TRUE_ANSWER_COUNT)

savedInstanceState.putInt(KEY_TRUE_ANSWER_COUNT, mTrueAnswerCount)
Copy the code

OK! Finished! ヾ (◍ ° ∇ ° ◍) ノ ゙