안드로이드 4주차 정리

학습목표

  • Android Studio Logcat 창(Android 콘솔 또는 Android 모니터라고도 함)에 로깅 정보를 인쇄하는 방법.
  • Activity 및 Fragment lifecycle의 기본 사항
  • Activity가 liftecycle 상태 간에 이동할 때 호출되는 콜백
  • Activity lifecycle의 다른 시간에 작업을 수행하기 위해 lifecycle 콜백 메서드를 재정의하는 방법.
  • 앱에 로그를 남기기 위해 Timber 라이브러리를 사용하는 방법.

lifecycle(수명 주기)메서드와 기본적인 logging을 알아보자.

Activity 수명 주기는 Activity가 처음 초기화될 때부터 마지막으로 파괴되고 시스템이 메모리를 회수할 때까지 Activity가 거칠 수 있는 다양한 상태로 구성됩니다. 사용자가 앱을 시작하고, Activity 사이를 탐색하고, 앱 내부와 외부를 탐색하고, 앱을 나가면 Activity의 상태가 변경됩니다. 아래 다이어그램은 모든 Activity 수명 주기 상태를 보여줍니다. 이름에서 알 수 있듯이 이러한 상태는 Activity의 상태를 나타냅니다.

Activity 수명 주기 상태가 변경되면 일부 동작을 변경하거나 일부 코드를 실행하려는 경우가 많습니다. 따라서 Activity 클래스 자체와 AppCompatActivity와 같은 Activity의 모든 하위 클래스는 일련의 수명 주기 콜백 메서드를 구현합니다. Android는 활동이 한 상태에서 다른 상태로 이동할 때 이러한 콜백을 호출하며, 자체 활동에서 이러한 메서드를 재정의하여 이러한 수명 주기 상태 변경에 대한 응답으로 작업을 수행할 수 있습니다. 다음 다이어그램은 사용 가능한 재정의 가능한 콜백과 함께 수명 주기 상태를 보여줍니다.

프래그먼트에도 수명 주기가 있습니다. 프래그먼트의 수명 주기는 Activity의 수명 주기와 유사하므로 학습한 내용 중 많은 부분이 두 가지 모두에 적용됩니다. Activity 수명 주기는 Android의 기본 부분이며 간단한 앱에서 관찰하기 가장 쉽기 때문입니다. 다음은 프래그먼트 수명 주기에 대한 해당 다이어그램입니다.

이러한 콜백이 호출되는 시기와 각 콜백 메서드에서 수행할 작업을 아는 것이 중요합니다. 그러나 이 두 다이어그램은 모두 복잡하고 혼란스러울 수 있습니다. 여기서는 각 상태와 콜백이 의미하는 바를 읽는 대신 몇 가지 조사 작업을 수행하고 진행 상황에 대한 이해를 구축할 것입니다.

Step1 : logging과 onCreate메서드에 대한 설명

Android 수명 주기에 무슨 일이 일어나고 있는지 파악하려면 다양한 수명 주기 메서드가 호출되는 시기를 아는 것이 도움이 됩니다. 이것은 DessertClicker에서 문제가 발생하는 위치를 찾는 데 도움이 됩니다.

이를 수행하는 간단한 방법은 Android 로깅 API를 사용하는 것입니다. 로깅을 사용하면 앱이 실행되는 동안 콘솔에 짧은 메시지를 작성할 수 있으며 이를 사용하여 다른 콜백이 트리거될 때 표시할 수 있습니다.

  1. DessertClicker 스타터 앱을 다운로드하고 Android Studio에서 엽니다.
  2. 앱을 컴파일하여 실행하고 디저트 사진을 여러 번 탭합니다. 판매된 디저트 값과 총 달러 금액이 어떻게 변경되는지 확인합니다.
  3. MainActivity.kt를 열고 이 활동에 대한 onCreate() 메서드를 검사합니다.

활동 수명 주기 다이어그램에서 이 콜백을 이전에 사용한 적이 있기 때문에 onCreate() 메서드를 인식했을 수 있습니다. 모든 Activity가 구현해야 하는 유일한 메서드입니다. onCreate() 메서드는 Activity에 대해 일회성 초기화를 수행해야 하는 곳입니다. 예를 들어 onCreate()에서 레이아웃을 확장하거나 클릭 리스너를 정의하거나 데이터 바인딩을 설정합니다.

onCreate() 수명 주기 메서드는 Activity가 초기화된 직후(메모리에 새 Activity 객체가 생성될 때) 한 번 호출됩니다. onCreate()가 실행된 후 Activity가 생성된 것으로 간주됩니다.

참고: onCreate() 메서드는 재정의입니다. 수명 주기 메서드를 재정의하는 경우 즉시 super.onCreate()를 호출해야 합니다.

  1. onCreate() 메서드에서 super.onCreate() 호출 직후에 다음 줄을 추가합니다. 필요한 경우 Log 클래스를 가져옵니다. (Mac에서 Alt+Enter 또는 Option+Enter를 누르고 가져오기를 선택합니다.)
Log.i("MainActivity", "onCreate Called")

Log 클래스는 Logcat에 메시지를 씁니다. 이 명령에는 세 부분이 있습니다.

Log.메세지의 심각도(로그 태그, 실제 로그 메세지)
  • 로그 메시지의 심각도, 즉 메시지의 중요성입니다. 이 경우 Log.i() 메서드는 정보 메시지를 작성합니다. Log 클래스의 다른 메서드에는 오류의 경우 Log.e() 또는 경고의 경우 Log.w()가 포함됩니다.
  • 로그 태그(이 경우 "MainActivity"). 태그는 Logcat에서 로그 메시지를 더 쉽게 찾을 수 있게 해주는 문자열입니다. 태그는 일반적으로 클래스의 이름입니다.
  • 실제 로그 메시지, 이 경우 "onCreate 호출"인 짧은 문자열입니다.
  1. DessertClicker 앱을 컴파일하고 실행합니다. 디저트를 탭할 때 앱에서 동작 차이가 표시되지 않습니다. Android Studio의 화면 하단에서 Logcat 탭을 클릭합니다.

    Logcat은 메시지 로깅을 위한 콘솔입니다. Log.i() 메서드 또는 다른 Log 클래스 메서드를 사용하여 명시적으로 로그에 보내는 메시지를 포함하여 앱에 대한 Android의 메시지가 여기에 표시됩니다.

  2. Logcat 창에서 검색 필드에 I/MainActivity를 입력합니다.

Logcat에는 많은 메시지가 포함될 수 있으며 대부분은 사용자에게 유용하지 않습니다. 다양한 방법으로 Logcat 항목을 필터링할 수 있지만 검색이 가장 쉽습니다. MainActivity를 코드에서 로그 태그로 사용했으므로 해당 태그를 사용하여 로그를 필터링할 수 있습니다. 시작 부분에 I/를 추가하는 것은 이것이 Log.i()에 의해 생성된 정보 메시지임을 의미합니다.

로그 메시지에는 날짜와 시간, 패키지 이름(com.example.android.dessertclicker), 로그 태그(시작 부분에 I/ 포함) 및 실제 메시지가 포함됩니다. 이 메시지가 로그에 나타나므로 onCreate()가 실행되었음을 알 수 있습니다.

Step2: onStart() 메서드 구현

onStart() 수명 주기 메서드는 onCreate() 직후에 호출됩니다. onStart()가 실행된 후 Activity가 화면에 표시됩니다. Activity를 초기화하기 위해 한 번만 호출되는 onCreate()와 달리 onStart()는 Activity의 수명 주기에서 여러 번 호출될 수 있습니다.

onStart()는 onStop() 수명 주기 메서드와 쌍을 이룹니다. 사용자가 앱을 시작한 다음 기기의 홈 화면으로 돌아가면 Activity가 중지되고 더 이상 화면에 표시되지 않습니다.

  1. Android Studio에서 MainActivity.kt를 연 상태에서 코드 > 메서드 재정의를 선택하거나 Ctrl+o를 누릅니다. 이 클래스에서 재정의할 수 있는 모든 메서드의 방대한 목록이 포함된 대화 상자가 나타납니다.

  2. 검색하려면 onStart를 입력하기 시작합니다. 일치하는 다음 항목으로 스크롤하려면 아래쪽 화살표를 사용합니다. 목록에서 onStart()를 선택하고 확인을 클릭하여 재정의 코드를 삽입합니다. 코드는 다음과 같습니다.

override fun onStart() {
   super.onStart()
}

팁: Android Studio는 재정의된 메서드 코드를 클래스에서 다음으로 사용 가능한 적절한 위치에 삽입합니다. 수명 주기 재정의를 특정 위치(예: 클래스 끝 부분)에 두려면 재정의 메서드를 사용하기 전에 삽입 지점을 설정하세요.

  1. onStart() 메서드 내에서 로그 메시지를 추가합니다.
override fun onStart() {
   super.onStart()

   Log.i("MainActivity", "onStart Called")
}
  1. DessertClicker 앱을 컴파일 및 실행하고 Logcat 창을 엽니다. 검색 필드에 I/MainActivity를 입력하여 로그를 필터링합니다. onCreate() 및 onStart() 메서드가 차례로 호출되었으며 Activity가 화면에 표시됩니다.

  2. 기기의 홈 버튼을 누른 후 최근 화면을 이용하여 활동으로 돌아갑니다. 활동은 모두 동일한 값으로 중단된 위치에서 다시 시작되고 onStart()는 Logcat에 두 번째로 기록됩니다. 또한 onCreate() 메서드는 일반적으로 다시 호출되지 않습니다.

참고: 장치를 실험하고 수명 주기 콜백을 관찰할 때 장치를 회전할 때 비정상적인 동작을 확인할 수 있습니다. 다음에서 해당 동작에 대해 알아봅니다.

logging을 위해 Timber를 사용해보자.

이 작업에서는 Timber라는 널리 사용되는 로깅 라이브러리를 사용하도록 앱을 수정합니다. Timber는 내장 Android Log 클래스에 비해 몇 가지 장점이 있습니다.

  • 클래스 이름을 기반으로 로그 태그를 생성합니다.
  • Android 앱의 릴리스 버전에서 로그가 표시되지 않도록 도와줍니다.
  • crash-reporting 라이브러리와의 통합을 허용합니다.

Step 1: Add Gradle에 Timber 라이브러리 추가하기.

  1. GitHub의 Timber 프로젝트에 대한 이 링크를 방문하여 다운로드 제목 아래 implementation이라는 단어로 시작하는 코드 줄을 복사합니다. 버전 번호는 다를 수 있지만 코드 행은 다음과 같이 보일 것입니다.
implementation 'com.jakewharton.timber:timber:4.7.1'
  1. build.gradle(모듈: 앱) 파일을 엽니다.
  2. dependencies section 안에, 복사한 코드를 붙여넣기 합니다.
  3. Sync Now를 클릭합니다.

Step2: 애플리케이션 클래스 생성 및 Timber 초기화

이 단계에서는 Application 클래스를 만듭니다. Application은 전체 앱에 대한 전역 애플리케이션 상태를 포함하는 기본 클래스입니다. 또한 운영 체제가 앱과 상호 작용하는 데 사용하는 주요 개체입니다. 지정하지 않으면 Android에서 사용하는 기본 Application 클래스가 있으므로 앱을 만들기 위해 특별한 작업을 수행할 필요 없이 항상 앱에 대해 생성된 Application 개체가 있습니다.

Timber는 전체 앱이 이 로깅 라이브러리를 사용하고 다른 모든 것이 설정되기 전에 라이브러리를 한 번 초기화해야 하기 때문에 Application 클래스를 사용합니다. 이와 같은 경우 Application 클래스를 하위 클래스로 분류하고 고유한 사용자 정의 구현으로 기본값을 재정의할 수 있습니다.

경고: 클래스는 모든 활동보다 먼저 생성되고 전역 상태를 보유할 수 있기 때문에 Application 클래스에 고유한 코드를 추가하고 싶을 수 있습니다. 그러나 전역적으로 사용 가능한 읽기 및 쓰기 가능한 정적 변수를 만드는 것은 오류가 발생하기 쉬운 것처럼 Application 클래스를 남용하기 쉽습니다. 코드가 실제로 필요한 경우가 아니면 Application 클래스에 활동 코드를 넣지 마십시오.

애플리케이션 클래스를 생성한 후에는 Android 매니페스트에서 클래스를 지정해야 합니다.
1. 디저트 클릭커 패키지에서 ClickerApplication이라는 새로운 Kotlin 클래스를 생성합니다.

package com.example.android.dessertclicker

class ClickerApplication {
}
  1. 클래스 정의를 Application의 하위 클래스로 변경하고 필요한 경우 Application 클래스를 가져옵니다.
class ClickerApplication : Application() {
}
  1. onCreate() 메서드를 재정의하려면 코드 > 메서드 재정의를 선택하거나 Ctrl+o를 누릅니다.
class ClickerApplication : Application() {
   override fun onCreate() {
       super.onCreate()
   }
}
  1. 해당 onCreate() 메서드 내에서 Timber 라이브러리를 초기화합니다.
override fun onCreate() {
    super.onCreate()

    Timber.plant(Timber.DebugTree())
}

이 코드는 Activity에서 라이브러리를 사용할 수 있도록 앱의 Timber 라이브러리를 초기화합니다.

  1. AndroidManifest.xml을 엽니다.
  2. 요소의 맨 위에 ClickerApplication 클래스에 대한 새 속성을 추가하여 Android가 기본 클래스 대신 Application 클래스를 사용한다는 것을 알 수 있도록 합니다.
<application
   android:name=".ClickerApplication"
   ....
             >

참고: Android 매니페스트에 사용자 지정 애플리케이션 클래스를 추가하지 않으면 앱이 오류 없이 실행됩니다. 그러나 앱은 클래스를 사용하지 않으며 Timber의 로깅 정보는 절대 볼 수 없습니다.

Step3: Timber로 log문 추가하기.

이 단계에서는 Timber를 사용하도록 Log.i() 호출을 변경한 다음 다른 모든 수명 주기 메서드에 대한 로깅을 구현합니다.

  1. MainActivity를 열고 onCreate()로 스크롤합니다. Log.i()를 Timber.i()로 바꾸고 로그 태그를 제거하십시오.
Timber.i("onCreate called")

Log 클래스와 마찬가지로 Timber도 정보 메시지에 i() 메서드를 사용합니다. Timber를 사용하면 로그 태그를 추가할 필요가 없습니다. Timber는 자동으로 클래스 이름을 로그 태그로 사용합니다.

  1. onStart()메서드도 똑같이 바꿉니다.

  2. DessertClicker 앱을 컴파일 및 실행하고 Logcat을 엽니다. onCreate() 및 onStart()에 대해 여전히 동일한 로그 메시지가 표시되지만 이제는 Log 클래스가 아닌 Timber에서 이러한 메시지를 생성하고 있습니다.

  3. MainActivity에서 나머지 수명 주기 메서드를 재정의하고 각각에 대해 Timber 로그 문을 추가합니다. 코드는 다음과 같습니다.

override fun onResume() {
   super.onResume()
   Timber.i("onResume Called")
}

override fun onPause() {
   super.onPause()
   Timber.i("onPause Called")
}

override fun onStop() {
   super.onStop()
   Timber.i("onStop Called")
}

override fun onDestroy() {
   super.onDestroy()
   Timber.i("onDestroy Called")
}

override fun onRestart() {
   super.onRestart()
   Timber.i("onRestart Called")
}
  1. DessertClicker를 다시 컴파일 및 실행하고 Logcat을 검사합니다. 이번에는 onCreate() 및 onStart() 외에도 onResume() 수명 주기 콜백에 대한 로그 메시지가 있음을 알 수 있습니다.

Activity가 처음부터 시작되면 다음 세 가지 수명 주기 콜백이 모두 순서대로 호출되는 것을 볼 수 있습니다.

  • onCreate()를 사용하여 앱을 만듭니다.
  • onStart()를 사용하여 시작하고 화면에 표시합니다.
  • onResume()을 사용하여 액티비티에 포커스를 주고 사용자가 액티비티와 상호 작용할 수 있도록 준비합니다

onResume() 메서드는 재개할 항목이 없더라도 시작 시 호출됩니다.

Error: Module was compiled with an incompatible version of Kotlin. The binary version of its metadata is 1.5.1, expected version is 1.1.16.
컴파일 후 실행하려니 에러가 발생했다. 코틀린 버전 문제인것 같아서 build.gradle(Project)에서 ext.kotlin_version을 최신 버전으로 높혀줬더니 문제가 해결되었다.

수명주기 메서드의 동작하는 상황 살펴보기

사용 사례 1: Activity 열기 및 닫기

가장 기본적인 사용 사례부터 시작합니다. 앱을 처음으로 시작한 다음 앱을 완전히 종료하는 것입니다.

  1. DessertClicker 앱이 아직 실행되고 있지 않은 경우 컴파일하고 실행합니다. 본 것처럼 onCreate(), onStart() 및 onResume() 콜백은 Activity가 처음 시작될 때 호출됩니다.

  1. 컵케이크를 몇번 클릭해봅니다.

  2. 기기에서 뒤로 버튼을 탭합니다. Logcat에서 onPause(), onStop() 및 onDestroy()가 순서대로 호출됩니다.

    이 경우 뒤로 버튼을 사용하면 Activity(및 앱)가 완전히 닫힙니다. onDestroy() 메소드의 실행은 Activity가 완전히 종료되었고 Garbage Collet가 될 수 있음을 의미합니다. 가비지 컬렉션은 더 이상 사용하지 않을 개체의 자동 정리를 의미합니다. onDestroy()가 호출된 후 OS는 해당 리소스를 삭제할 수 있음을 알고 해당 메모리 정리를 시작합니다.


    코드가 Activity의 finish() 메서드를 수동으로 호출하거나 사용자가 앱을 강제 종료하는 경우에도 Activity가 완전히 종료될 수 있습니다. (예를 들어, 사용자는 창 모서리에 있는 X를 클릭하여 최근 화면에서 앱을 강제 종료할 수 있습니다.) Android 시스템은 또한 앱이 한동안 화면에 표시되지 않은 경우 자체적으로 Activity를 종료할 수 있습니다. Android는 배터리를 절약하고 앱의 리소스를 다른 앱에서 사용할 수 있도록 하기 위해 이 작업을 수행합니다.

  3. 최근 화면을 사용하여 앱으로 돌아갑니다. 다음은 Logcat입니다.

    Activity는 이전 단계에서 소멸되었으므로 앱으로 돌아가면 Android에서 새 Activity를 시작하고 onCreate(), onStart() 및 onResume() 메서드를 호출합니다. 이전 Activity에서 주문한 디저트 항목의 수와 총 가격은 유지되지 않았습니다. 0으로 재설정됩니다. 앱에서 이 동작을 원하지 않을 수 있습니다. 이 문제는 다음에 해결해 볼 것입니다.

    여기서 핵심은 onCreate() 및 onDestroy()가 단일 Activity 인스턴스의 수명 동안 한 번만 호출된다는 것입니다. onCreate()는 앱을 처음으로 초기화하고 onDestroy()는 앱에서 사용하는 리소스를 정리합니다.

    onCreate() 메서드는 중요한 단계입니다. 여기에서 모든 최초 초기화가 진행되고, 레이아웃을 확장(inflate)하여 처음으로 레이아웃을 설정하고, 변수를 초기화합니다.

    사용 사례 2: Activity에서 벗어났다가 다시 Activity로 돌아가기

    이제 앱을 시작하고 완전히 닫았으므로 Activity가 처음 생성될 때 대부분의 수명 주기 상태를 보았습니다. 또한 Activity가 완전히 종료되고 파괴될 때 진행되는 모든 수명 주기 상태를 보았습니다. 그러나 사용자는 Android 기반 장치와 상호 작용할 때 앱 간 전환, 홈으로 돌아가기, 새 앱 시작, 전화 통화와 같은 기타 외부 활동으로 인한 중단 처리와 같은 다양한 작업을 수행합니다.

    사용자가 해당 Activity에서 벗어날 때마다 Activity가 완전히 종료되지는 않습니다.

  • Activity가 더 이상 화면에 표시되지 않는 경우 이를 Activity를 Background에 배치하는 것으로 알려져 있습니다. (반대는 Activity가 Foreground나 화면에 있을 때입니다.)

  • 사용자가 앱으로 돌아오면 동일한 Activity가 다시 시작되고 다시 표시됩니다. 수명 주기의 이 부분을 앱의 가시적 수명 주기(visible lifecycle)라고 합니다.

    앱이 Background에 있을 때 시스템 리소스와 배터리 수명을 보존하기 위해 활발히 실행되어서는 안 됩니다. Activity 수명 주기와 해당 콜백을 사용하여 진행 중인 작업을 일시 중지하여 앱이 Background로 이동할 때를 알 수 있습니다. 그런 다음 앱이 Foreground로 전환되면 해당 작업을 다시 시작합니다.

예를 들어 컴퓨팅 리소스에 크게 의존하는 앱을 생각해 보십시오. 이 앱은 기기의 CPU를 사용하여 많은 계산을 할 수 있습니다. 처리 능력과 배터리 수명은 일반적으로 모바일 장치에서 제한되므로 Android 런타임 시스템은 리소스의 균형을 맞춰야 합니다. Background 프로세스가 성능을 저하시키거나 휴대폰 배터리를 조기에 소모할 수 있으므로 Android는 Foreground에서 실행되지 않는 앱에 대한 리소스 사용을 중지할 수 있습니다.

이 다음 단계에서는 앱이 Background로 갔다가 다시 Foreground로 돌아갈 때의 활동 수명 주기를 살펴봅니다.

  1. DessertClicker 앱을 실행한 상태에서 컵케이크를 몇 번 클릭합니다.

  2. 기기의 홈 버튼을 누르고 Android Studio에서 Logcat을 관찰합니다. onPause() 메서드와 onStop() 메서드가 호출되지만 onDestroy()는 호출되지 않습니다. 홈 화면으로 돌아가면 앱이 완전히 종료되지 않고 앱이 Background로 전환됩니다.

    onPause()가 호출되면 앱에 더 이상 포커스가 없습니다. onStop() 후에는 앱이 더 이상 화면에 표시되지 않습니다. Activity가 중지되었지만 Activity 개체는 여전히 Background에서 메모리에 있습니다. Activity는 파괴되지 않았습니다. 사용자가 앱으로 돌아갈 수 있으므로 Android는 주변에 활동 리소스를 유지합니다.

  3. 최근 화면을 사용하여 앱으로 돌아갑니다. Logcat에서 활동이 onRestart() 및 onStart()로 다시 시작된 다음 onResume()으로 다시 시작되었음을 알 수 있습니다.

  4. 기기의 최근 화면에 몇 개의 앱이 표시되도록 DessertClicker 이외의 앱을 하나 이상 시작하세요.

  5. 최근 화면을 불러오고 다른 최근 활동을 엽니다. 그런 다음 최근 앱으로 돌아가서 DessertClicker를 다시 Foreground로 가져옵니다.

    여기에서 홈 버튼을 눌렀을 때와 동일한 콜백이 Logcat에 표시됩니다. onPause() 및 onStop()은 앱이 백그라운드로 들어갈 때 호출되고, 다시 돌아올 때 onRestart(), onStart(), onResume()이 호출됩니다.

    여기서 중요한 점은 사용자가 Activity를 탐색할 때 onStart() 및 onStop()이 여러 번 호출된다는 것입니다. 앱이 Background로 이동할 때 앱을 중지하거나 Foreground로 돌아갈 때 다시 시작하려면 이러한 메서드를 재정의해야 합니다.

    그렇다면 onRestart()는 어떻습니까? onRestart() 메서드는 onCreate()와 매우 유사합니다. Activity가 표시되기 전에 onCreate() 또는 onRestart()가 호출됩니다. onCreate() 메서드는 처음에만 호출되고 onRestart()는 그 이후에 호출됩니다. onRestart() 메서드는 활동이 처음 시작되지 않는 경우에만 호출하려는 코드를 넣는 곳입니다.

Use case 3: 부분적으로 Activity 숨기기

앱이 시작되고 onStart()가 호출되면 앱이 화면에 표시된다는 것을 배웠습니다. 앱이 다시 시작되고 onResume()이 호출되면 앱이 사용자 포커스를 얻습니다. 앱이 완전히 화면에 표시되고 사용자 포커스가 있는 수명 주기 부분을 대화형 수명 주기(interactive lifecycle)라고 합니다.

앱이 백그라운드로 전환되면 onPause() 이후에 포커스가 사라지고 onStop() 이후에는 앱이 더 이상 표시되지 않습니다.

포커스와 가시성의 차이는 활동이 화면에 부분적으로 표시될 수 있지만 사용자 포커스가 없을 수 있기 때문에 중요합니다. 이 단계에서는 활동이 부분적으로 표시되지만 사용자 포커스가 없는 한 가지 경우를 살펴봅니다.

  1. DessertClicker 앱을 실행한 상태에서 화면 오른쪽 상단의 공유 버튼을 클릭합니다.

    공유 activity는 화면 하단에 나타나지만 Activity는 여전히 상단 절반에 표시됩니다.

  2. Logcat을 검사하고 onPause()만 호출되었음을 확인합니다.

    이 사용 사례에서는 Activity가 여전히 부분적으로 표시되기 때문에 onStop()이 호출되지 않습니다. 그러나 Activity에는 사용자 포커스가 없으며 사용자는 Activity와 상호 작용할 수 없습니다. Foreground에 있는 "공유" Activity에는 사용자 포커스가 있습니다.

    이 차이가 왜 중요한가요? 이전의 계산 집약적인 앱을 고려하십시오. 앱이 Background에 있을 때 중지되지만 앱이 부분적으로 가려지면 계속 실행되기를 원할 수 있습니다. 이 경우 onStop()에서 종료합니다. Activity가 부분적으로 가려질 때 앱도 중지되도록 하려면 onPause()에 앱을 종료하는 코드를 삽입합니다.

    onPause()에서 실행되는 코드는 다른 것이 표시되지 않도록 차단하므로 onPause()의 코드를 가볍게 유지하십시오. 예를 들어 전화가 오면 onPause()의 코드가 전화 수신 알림을 지연시킬 수 있습니다.

  3. 앱으로 돌아가려면 공유 대화 상자 외부를 클릭하고 onResume()이 호출된 것을 확인합니다.

    onResume() 및 onPause() 모두 포커스와 관련이 있습니다. onResume() 메서드는 액티비티에 포커스가 있을 때 호출되고 onPause()는 액티비티가 포커스를 잃으면 호출됩니다.

프래그먼트 수명 주기 살펴보기

Android 프래그먼트 수명 주기는 Activity 수명 주기와 유사하며 여러 프래그먼트별 메서드가 있습니다.

이 작업에서는 이전 코드랩에서 빌드한 AndroidTrivia 앱을 살펴보고 일부 로깅을 추가하여 Fragment 수명 주기를 탐색합니다.

AndroidTrivia 앱의 각 화면은 Fragment입니다.

작업을 단순하게 유지하기 위해 이 작업에서 Timber 라이브러리가 아닌 Android 로깅 API를 사용합니다.

  1. 이전 Codelab 중 하나에서 AndroidTriviaNavigation 앱을 열거나 GitHub에서 AndroidTriviaNavigation 솔루션 코드를 다운로드합니다.

  2. TitleFragment.kt 파일을 엽니다. Android Studio는 앱을 다시 빌드할 때까지 바인딩 오류 및 해결되지 않은 참조 오류를 표시할 수 있습니다.

  3. onCreateView() 메서드까지 아래로 스크롤합니다. 여기에서 Fragment의 레이아웃이 확장되고(inflate) 데이터 바인딩이 발생합니다.

  4. setHasOptionsMenu() 행과 return에 대한 최종 호출 사이에 onCreateView() 메서드에 로깅 문을 추가합니다.

setHasOptionsMenu(true)

Log.i("TitleFragment", "onCreateView called")

return binding.root
  1. onCreateView() 메서드 바로 아래에 나머지 Fragment 수명 주기 메서드 각각에 대한 로깅 문을 추가합니다. 코드는 다음과 같습니다.
override fun onAttach(context: Context) {
   super.onAttach(context)
   Log.i("TitleFragment", "onAttach called")
}
override fun onCreate(savedInstanceState: Bundle?) {
   super.onCreate(savedInstanceState)
   Log.i("TitleFragment", "onCreate called")
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    Log.i("TitleFragment", "onViewCreated called")
}

override fun onStart() {
   super.onStart()
   Log.i("TitleFragment", "onStart called")
}
override fun onResume() {
   super.onResume()
   Log.i("TitleFragment", "onResume called")
}
override fun onPause() {
   super.onPause()
   Log.i("TitleFragment", "onPause called")
}
override fun onStop() {
   super.onStop()
   Log.i("TitleFragment", "onStop called")
}
override fun onDestroyView() {
   super.onDestroyView()
   Log.i("TitleFragment", "onDestroyView called")
}
override fun onDetach() {
   super.onDetach()
   Log.i("TitleFragment", "onDetach called")
}
  1. 앱을 컴파일 및 실행하고 Logcat을 엽니다.

  2. 검색 필드에 I/TitleFragment를 입력하여 로그를 필터링합니다. 앱이 시작되면 Logcat은 다음과 같이 보일 것입니다.

21933-21933/com.example.android.navigation I/TitleFragment: onAttach called
21933-21933/com.example.android.navigation I/TitleFragment: onCreate called
21933-21933/com.example.android.navigation I/TitleFragment: onCreateView called
21933-21933/com.example.android.navigation I/TitleFragment: onViewCreated called
21933-21933/com.example.android.navigation I/TitleFragment: onStart called
21933-21933/com.example.android.navigation I/TitleFragment: onResume called

Fragment의 전체 시작 수명 주기를 볼 수 있습니다.

  • onAttach(): 프래그먼트가 소유자 Activity과 연결될 때 호출됩니다.

  • onCreate(): 액티비티에 대한 onCreate()와 유사하게, 프래그먼트에 대한 onCreate()는 초기 프래그먼트 생성(레이아웃 제외)을 수행하기 위해 호출됩니다.

  • onCreateView(): 프래그먼트의 레이아웃을 확장하기 위해 호출됩니다.

  • onViewCreated(): onCreateView()가 반환된 직후에 호출되지만 저장된 상태가 뷰에 복원되기 전에 호출됩니다.

  • onStart(): Fragment가 화면에 표시될 때 호출됩니다. Activity의 onStart()와 병행합니다.

  • onResume(): 프래그먼트가 사용자 포커스를 얻을 때 호출됩니다. Activity의 onResume()과 병행합니다.

  1. 플레이 버튼을 눌러 퀴즈 게임을 진행하고 지금 Logcat을 확인하세요.
21933-21933/com.example.android.navigation I/TitleFragment: onPause called
21933-21933/com.example.android.navigation I/TitleFragment: onStop called
21933-21933/com.example.android.navigation I/TitleFragment: onDestroyView called

다음 Fragment를 열면 TitleFragment가 닫히고 다음과 같은 수명 주기 메서드가 호출됩니다.

  • onPause(): 프래그먼트가 사용자 포커스를 잃을 때 호출됩니다. Activity의 onPause()와 병행합니다.

  • onStop(): 프래그먼트가 더 이상 화면에 표시되지 않을 때 호출됩니다. 활동의 onStop()과 병행합니다.

  • onDestroyView(): 프래그먼트의 View가 더 이상 필요하지 않을 때 호출되어 해당 View와 관련된 리소스를 정리합니다.

    앱에서 위로 버튼(화면의 왼쪽 상단 모서리에 있는 화살표)을 탭하여 제목 부분으로 돌아갑니다.

12422-12422/com.example.android.navigation I/TitleFragment: onCreateView called
12422-12422/com.example.android.navigation I/TitleFragment: onViewCreated called
12422-12422/com.example.android.navigation I/TitleFragment: onStart called
12422-12422/com.example.android.navigation I/TitleFragment: onResume called

이번에는 onAttach() 및 onCreate()가 프래그먼트를 시작하기 위해 호출되지 않을 수 있습니다. 프래그먼트 객체는 여전히 존재하고 여전히 소유자 Activity에 연결되어 있으므로 수명 주기는 onCreateView()로 다시 시작됩니다.

  1. 기기의 홈 버튼을 누릅니다. Logcat에서 onPause() 및 onStop()만 호출됩니다. 이것은 Activity의 경우와 동일한 동작입니다. 홈으로 돌아가면 Activity과 프래그먼트가 Background에 놓입니다.

  2. 최근 화면을 사용하여 앱으로 돌아갑니다. 액티비티에서 발생한 것처럼 onStart() 및 onResume() 메서드가 호출되어 프래그먼트을 Foreground으로 반환합니다.

좋은 웹페이지 즐겨찾기