안녕하세요, DevHyeon 입니다.

오늘은 Fragment 이론에서 학습한 내용에 대해서 실습을 통해 직접 알아보도록 하겠습니다.

Fragmnet LifeCycle 이론 바로가기


fragment 를 삽입하는 2가지 방법을 실습해 볼것입니다.

a. Layout.xml 에서 <fragment> 요소로 삽입하는 방법

b. Code 를 사용하여 기존의 ViewGroup 에 추가하여 Layout 에 삽입하는 방법

 

생명주기는 총 2가지 테스트를 통해서 확인을 해볼겁니다.

c. Actvity 에서 생성된 Fragment 가 Activity 생명주기에 따라 어떻게 변하는가?

d. Activity 에서 생성된 Fragment 가 Activity 는 Running 상태를 유지하고 있을 때, 변화되는 상황의 Fragment 의 생명주기 알아보기


1. Fragment 삽입 실습

사전작업

1.  Fragment 에 사용되는 layout.xml 만들기 :) [ UI 가 필요없는 Fragment 의 경우 생략 가능합니다. ]

// UI 가 필요없는 Fragment 는 생략 가능합니다. 기억하시죠? Fragment 는 동작 or UI 로 사용된다는거~

 

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Sample Fragment"
        android:textSize="32sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

2. Fragment를 상속받은 나만의 Fragment 클래스 만들기 :)

//저는 ViewBinding 을 사용하여 작성한 코드입니다!

class SampleFragment : Fragment() {
    private var _binding: FragmentSampleBinding? = null
    private val binding get() = _binding!!

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        _binding = FragmentSampleBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onDestroy() {
        super.onDestroy()
        _binding = null
    }
}

 

 

a. Layout.xml 에서 <fragment> 요소로 삽입하는 방법
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <fragment
        android:id="@+id/fragment3"
        android:name="com.devhyeon.fragmentlifecycle.fragments.SampleFragment"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    
</androidx.constraintlayout.widget.ConstraintLayout>

<fragment> 속성에 tools:layout="@layout/fragment_sample"  를 추가하여 미리 확인해볼 수 있어요.

추가하기 전

tools:layout="@layout/fragment_sample" 추가 전

tools:layout="@layout/fragment_sample" 추가 후

 

b. Code 를 사용하여 기존의 ViewGroup 에 추가하여 Layout 에 삽입하는 방법

1. fragment 가 Activity 에서 삽입될 수 있는 ViewGroup 을 xml 에 추가해주어야 합니다. (id 는 필수~)

 * FrameLayout 뿐만 아니라, 다른 ViewGroup 인 Constraint, Linear, Table 이런 Layout 을 사용할 수도 있습니다.

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <FrameLayout
        android:id="@+id/frameSample"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    </FrameLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

2. Fragment 를 삽입하는 코드 작성

class SampleActivity : AppCompatActivity() {
    lateinit var binding : ActivitySampleBinding
    companion object {
        private val TAG = "DevHyeon : " + SampleActivity::class.java.name
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        println("$TAG : onCreate()")
        /** ViewBinding 의 코드이므로, Fragment LifeCycle Test 에 직접적인 연관이 없습니다. */
        binding = ActivitySampleBinding.inflate(layoutInflater)
        setContentView(binding.root)

		/** Fragement 삽입 코드 */
        if (savedInstanceState == null) {
            supportFragmentManager
            	.beginTransaction()
                .add(binding.frameSample.id, BodyFragment())
                .commit()
        }
    }
}

이렇게하면, Activity 가 onCreate() 되는 시점에 삽입이 가능합니다 :)

 


2. 생명주기 확인 실습

c. Activity 에서 생성된 Fragment 는 Activity 생명주기에 따라 어떻게 변하는가?

Activity 의 생성부터 파괴까지 일어나는 로그

Activity 실행

1. 액티비티 생성                        👉 Activity onCreate()

2. 프래그먼트 생성                    👉 Fragment onAttach() ~ onViewStateRestored()

3. 프래그먼트 실행                    👉 Fragment onStart()

4. 액티비티 실행                        👉 Activity onStart()

5. 액티비티 run상태                   👉 Activity onResume()
6. 프래그먼트 run상태                👉Fragment onResume()

 

Activity 정지

7. 프래그먼트 상호작용 불가        👉 Fragment onPuase()

8. 액티비티 상호작용불가            👉 Activity onPuase()

9. 프래그먼트 정지                      👉 Fragment onStop()

10. 액티비티 정지                        👉 Activity onStop()

11. 프래그먼트 상태저장               👉 Fragment onSaveInstanceState()

 

Activity 재실행

12. 액티비티 재실행                     👉 Activity onRestart()

13. 프래그먼트 실행                    👉 Fragment onStart()

14. 액티비티 실행                        👉 Activity onStart()

15. 액티비티 run상태                   👉 Activity onResume()
16. 프래그먼트 run상태               👉Fragment onResume()

 

Activity 종료

17. 프래그먼트 상호작용 불가      👉 Fragment onPuase()

18. 액티비티 상호작용불가         👉 Activity onPuase()

19. 프래그먼트 정지                   👉 Fragment onStop()

20. 액티비티 정지                     👉 Activity onStop()

21. 프래그먼트 파괴                   👉 Fragment onDestroyView() ~ onDestroy() 

22. 액티비티 파괴                     👉 Activity onDestroy()

 

Activity 생성 이후에 onPuase(사용자와의 상호작용 불가) 부터 onResume(사용자와의 상호작용 가능) 까지의 로그

Activity 실행

1. 액티비티 생성                         👉 Activity onCreate()

2. 프래그먼트 생성                     👉 Fragment onAttach() ~ onViewStateRestored()

3. 프래그먼트 실행                     👉 Fragment onStart()

4. 액티비티 실행                        👉 Activity onStart()

5. 액티비티 run상태                    👉 Activity onResume()
6. 프래그먼트 run상태                👉Fragment onResume()

 

Activity 와 사용자 상호작용 불가

7. 프래그먼트 상호작용 불가        👉 Fragment onPuase()

8. 액티비티 상호작용불가            👉 Activity onPuase()

 

Activity 와 사용자 상호작용 가능

9. 액티비티 run상태                    👉 ActivityonResume()
10. 프래그먼트 run상태                👉FragmentonResume()

 

 

* 핵심포인트 :

Running 단계로 가는 과정에서는 Fragment LifeCycle 이후에 Activity 의 다음 LifeCycle 이 동작합니다.

Destroy 단계로 가는 과정에서는 Activity LifeCycle 이후에 Fragment 의 다음 LifeCycle 이 동작합니다.

 

이해가 어렵나요? 저는 이렇게 생각했습니다.

Activity 에 Fragment 를 보여줘야 하는 과정에서 Fragment 가 먼저 준비되지 않으면 Activity 는 찰나의 순간에 아무것도 보여주지 않는다.

Activity 를 제거해야하는 과정에서 Fragment 를 먼저 제거하면, Activity 는 찰나의 순간에 아무것도 보여주지 않는다.

 

어떤가요?  사용자를 중점으로 생각해보면 조금더 와닿을수도..

 

d. Activity 에서 생성된 Fragment 가 Activity 는 Running 상태를 유지하고 있을 때, 변화되는 상황의 Fragment 의 생명주기 알아보기

Activity 가 onResume() 까지 진행 한 이후에

Fragment 를 삽입하게 되면, Fragment LifeCycle 이 onResume() 까지 동작하는 것을 알 수 있습니다.

 

 

오늘의 결론

Fragment 와 Activity 에서 엮이는 LifeCycle 이 생각보다 복잡하기 때문에, 한번쯤은 직접 확인해보는게 좋을 것 같습니다.

Fragment LifeCycle 은 직접 실행시켜보고 로그를 확인해보는것이 좀더 빠른 이해를 도울 수 있습니다.

 

아래는 테스트에 사용한 코드원본입니다.

github.com/DevHyeon0312/Fragment-LifeCycle-with-Activity

 

 

❤️ 별거 없는 내용일지라도, 공감과 Star 하나하나가 저에게는 성취감이 됩니다! ❤️

1. Fragment 란?

Fragment 는 FragmentActivity 내에서 동작이나 UI(부분) 을 나타냅니다.
( FragmentActivity 는 추후 학습, Activity 의 한 종류라고 생각하고 넘어가시고 나중에 정리해두겠습니다. (Activity, AppBarActivity, AppcompatActivity, FragmentActivity 등등...)

 

2. Fragment 특징

1. 하나의 Activity 내에서 여러개의 Fragment를 결합하여 window 가 여러개인 UI 를 빌드할 수 있다.

2. Fragment 는 여러개의 Activity에서 재사용이 가능하다.

3. Fragment 는 자체적인 수명주기를 가지고, 자체적인 입력 이벤트를 수신할 수 있다.

4. Fragment 는 Activity 실행중에 추가 및 삭제가 가능하다.

5. Fragment 는 항상 Activity 내에서 사용되어야 한다. 이 때, Fragment 수명주기는 Activity 의 수명주기에 직접적인 영향을 받는다.

6. Frgment 를 Activity 에서 사용하는 Layout 에 추가하는 경우 해당 Fragment 는 해당 Activity 의 ViewGruop 에 속하게 되고,

자체적인 View Layout 을 정의한다.

7. Fragment 는 Layout.xml 에서 <fragment> 요소로 선언하거나, 기존의 ViewGroup 에 추가하는 방법을 사용하면 Code 에서 Fragment 를 Layout 에 삽입이 가능하다.

 

3. Fragment LifeCycle

https://developer.android.com/guide/fragments/lifecycle

 

 

1. Fragment LifeCycle 가져오기 ( kotlin )

this.lifecycle.currentState

onCreateView 에서 해당 코드 출력결과

2. View LifeCycle 가져오기 ( kotlin )

this.viewLifecycleOwner.lifecycle.currentState

onCreateView 에서 해당 코드 출력결과

Fragme LifeCycle 단계 정리

Fragment LifeCycle Method View LifeCylce explanation
INITIALIZED onAttach NULL 프래그먼트가 액티비티와 연결되는 순간에 호출
CREATED onCreate NULL 프래그먼트를 처음 생성할 때 호출
CREATED onCreateView INITIALIZED 프래그먼트에 UI 를 그려야하는 순간에 호출하고, 
프래그먼트에 UI 를 그린다면 view 를 반환.
만약 프래그먼트가 UI 를 그리지 않는다면, null 을 반환
CREATED onActivityCreated INITIALIZED 프래그먼트생성이 완료되었다는 것을 액티비티에 알릴 때 호출
CREATED onViewStateRestored CREATED 프래그먼트에 저장된 상태를 복원했을 때 호출
STARTED onStart STARTED 프래그먼트가 화면에 보여지는 순간에 호출
RESUMED onResume RESUMED 프래그먼트가 사용자와 상호작용을 하는 순간에 호출
STARTED onPause STARTED 프래그먼트가 사용자와 상호작용을 하지 못하는 순간에 호출
CREATED onStop CREATED 프래그먼트가 화면에서 사라지는 순간에 호출
CREATED onSavedInstanceState CREATED 프래그먼트의 상태를 저장할 때 호출
CREATED onDestroyView DESTROYED 프래그먼트의 UI 가 사라져야 하는 순간에 호출
DESTROYED onDestroy NULL 프래그먼트가 제거될 때 호출
DESTROYED onDetach NULL 프래그먼트가 액티비티와 연결이 끊어질 때 호출

* LifeCycle 이 NULL 일때 State 를 가져오려고 하면 에러가 발생한다는 당연한 사실을 기억하세요

 

Activity LifeCycle 과 비교하면, 더 복잡한 LiceCycle 을 가지고 있지만, 완전히 전혀 다른 느낌의 구조는 아닙니다.

 

결국 우리는 Activity 내에서 Fragment 를 결합하여 사용하기 때문에 Fragment 는 사용된 Activity 의 LifeCycle 의 영향에서 벗어날 수가 없습니다.

 

그렇다면, Activity 에 Fragment 를 결합할 때 발생하는 전체적인 LifeCycle 은 어떻게 되는지 알아보겠습니다.

 

https://stackoverflow.com/posts/58029686/revisions

이 그림만 봐서는 와...뭐야 이거? 싶으실 수 도 있습니다.

Android Fragment 실습에서 해당 동작에 대해 직접적으로 Log 를 찍어보면서 확인하는 글을 작성하겠습니다. :)

 

4. Fragment 특징별 설명

1. 하나의 Activity 내에서 여러개의 Fragment를 결합하여 window 가 여러개인 UI 를 빌드할 수 있다.

- 스마트폰에서의 메모장을 생각해볼까요? 첫 화면에서 제목(TitleFragment)들을 보여주고, 해당 제목을 누르면 내용(MemoFragment)
을 보여준다고 해보겠습니다.

- 태블릿에서는 어떨까요? 좌측에 제목(TitleFragment)들을 보여주고, 우측에 내용(MemoFragment) 보여줄 수도 있습니다.

즉, 태블릿에서는 하나의 Activity 에 동시에 TitleFragment 와 MemoFragment . 즉, 여러개의 Fragment 가 결합되어 사용된다는 것을 알 수 있습니다.

 

2. Fragment 는 여러개의 Activity에서 재사용이 가능하다.

- 스마트폰에서 첫화면(MainActivity) 에서 TitleFragment 만 보여주었다고, 해당 제목을 클릭했을 시에 새로운 상세화면(DetailActivity) 에서 MemoFragment 만 보여줄 수 있습니다. 이렇게 여러 Activity 에서 필요로 하는 Fragment 만을 결합하여 사용할 수 있습니다.

좌측 : 스마트폰, 우측 : 태블릿

 

3. Fragment 는 자체적인 수명주기를 가지고, 자체적인 입력 이벤트를 수신할 수 있다.

- 3. Fragment LifeCycle 설명 참조

 

4. Fragment 는 Activity 실행중에 추가 및 삭제가 가능하다.

- 실습예정

 

5. Fragment 는 항상 Activity 내에서 사용되어야 한다. 이 때, Fragment 수명주기는 Activity 의 수명주기에 직접적인 영향을 받는다.

- 3. Fragment LifeCycle 설명 참조

 

6. Frgment 를 Activity 에서 사용하는 Layout 에 추가하는 경우 해당 Fragment 는 해당 Activity 의 ViewGruop 에 속하게 되고,

자체적인 View Layout 을 정의한다.

 

7. Fragment 는 Layout.xml 에서 <fragment> 요소로 선언하거나, 기존의 ViewGroup 에 추가하는 방법을 사용하면 Code 에서 Fragment 를 Layout 에 삽입이 가능하다.

- 실습예정

 

 

 

5. 오늘의 결론

1. 실습을 통해서 알아보겠지만, 가장 중요한것은 Fragment 의 LifeCycle 을 Activity LifeCycle 과 함께 신경써야 한다는 것입니다.

Fragment LifeCycle 만 생각한채로 진행하면, 그 과정도 결과도 쉽지 않을 수 있습니다.

 

2. 저는 1Activity n Fragment 를 지향하지 않습니다. 그렇다고 해서 n Activity 0 Fragment 를 지향하지도 않습니다.

때에 따라서 적절한 n 개의 Activity 와, 재사용성이 필요하고 고려되는 측면들에서 n 개의 Fragment 를 사용하는 등으로

적절하게 섞어주는게 좋을 것 같습니다.

 

만약, 하나의 DeviceSize 만을 지원하는 앱이면 n Activity 0 Fragment 로 해도 되나요? 라는 질문을 받는다면

저는 그 Device에서 지원하는 앱이 그 내부적으로 재사용 가능한 UI 가 없습니까? 를 묻고 싶습니다.


모든 Activity 로 Fragment 를 대체할 수 있고, 1Activity n Fragment 로도 n Activity 를 대체할 수 있습니다.

A가 좋으니 A만 쓴다.

B가 좋으니 B만 쓴다.

이런 생각보다는 A의 장점과 B의 장점을 고려하여 상황에 맞게 쓴다. 로 생각하시면 좋을 것 같습니다.


ps. 정말 극단적으로 A보다 B가 모든 측면에서 좋다면, A라는 기술을 사라질 것입니다. (그것이 라이브러리라면, 더이상 업데이트를 지원하지 않거나, 없애거나 하는 등의 결과가 나오겠죠?)
ex. butterknife 는 공식적으로 업데이트하지 않겠다고 선언한 라이브러리입니다. viewBinding 을 사용하라고 안내하고 있습니다.

 

 

작성하다보니까 깨달은 것은 실습 글을 빨리 작성해야겠네요.

 

developer.android.com/reference/android/app/Fragment

 

Fragment  |  Android 개발자  |  Android Developers

 

developer.android.com

 

'BackUp (관리중지) > Android 이론' 카테고리의 다른 글

Android Service  (0) 2021.05.14
Android Coroutine [코루틴]  (0) 2021.05.04
[Android Jetpack] LiveData란,  (0) 2021.04.21
Activity 와 Activity LifeCycle 분석  (0) 2021.04.15
Android Context 에 대한 분석  (1) 2021.04.14

+ Recent posts