[Android ๊ธฐ์ดˆ] 7. Fragment, Fragment ์ƒ๋ช… ์ฃผ๊ธฐ, ๋ฐ์ดํ„ฐ ์ „๋‹ฌ ๋ฐฉ์‹
๋ฐ˜์‘ํ˜•

 

 

 

 

1. Fragment

 

 

 

ํ”„๋ž˜๊ทธ๋จผํŠธ  |  Android ๊ฐœ๋ฐœ์ž  |  Android Developers

์ด ํŽ˜์ด์ง€๋Š” Cloud Translation API๋ฅผ ํ†ตํ•ด ๋ฒˆ์—ญ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ํ”„๋ž˜๊ทธ๋จผํŠธ ์ปฌ๋ ‰์…˜์„ ์‚ฌ์šฉํ•ด ์ •๋ฆฌํ•˜๊ธฐ ๋‚ด ํ™˜๊ฒฝ์„ค์ •์„ ๊ธฐ์ค€์œผ๋กœ ์ฝ˜ํ…์ธ ๋ฅผ ์ €์žฅํ•˜๊ณ  ๋ถ„๋ฅ˜ํ•˜์„ธ์š”. Fragment๋Š” ์•ฑ UI์˜ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋ถ€๋ถ„์„ ๋‚˜

developer.android.com

  • ์•กํ‹ฐ๋น„ํ‹ฐ ์œ„์—์„œ ๋™์ž‘ํ•˜๋Š” ๋ชจ๋“ˆํ™”๋œ ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค
  • ์•ฑ UI์˜ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋ถ€๋ถ„์„ ๋‚˜ํƒ€๋ƒ„ (ํ™”๋ฉด ํ•˜๋‚˜๋ฅผ ๋…๋ฆฝ์ ์œผ๋กœ ์ž‘๋™ํ•˜๋Š” ๋ถ€๋ถ„ํ™”๋ฉด ์—ฌ๋Ÿฌ๊ฐœ๋กœ ๊ตฌํ˜„)
  • ๋‹จ๋…์œผ๋กœ ์กด์žฌํ•  ์ˆ˜ ์—†์œผ๋ฉฐ, ๋ฐ˜๋“œ์‹œ ์•กํ‹ฐ๋น„ํ‹ฐ ๋˜๋Š” ๋‹ค๋ฅธ ํ”„๋ž˜๊ทธ๋จผํŠธ๊ฐ€ ํ•„์š”ํ•จ
  • ์ž์ฒด ๋ ˆ์ด์•„์›ƒ์„ ์ •์˜ ๋ฐ ๊ด€๋ฆฌํ•˜๊ณ  ์ž์ฒด ์ˆ˜๋ช… ์ฃผ๊ธฐ๋ฅผ ๋ณด์œ ํ•˜๋ฉฐ ์ž์ฒด ์ž…๋ ฅ ์ด๋ฒคํŠธ๋ฅผ ์ฒ˜๋ฆฌ
  • ์žฅ์ 1. ์žฌ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•จ (ํ•œ ํ”„๋ž˜๊ทธ๋จผํŠธ์˜ ๊ฐ์ฒด๋Š” ๋‹ค์ˆ˜์˜ ์•กํ‹ฐ๋น„ํ‹ฐ์—์„œ ์ƒ์„ฑ ๊ฐ€๋Šฅ, UI ์ž‘์—…๋Ÿ‰ ๊ฐ์†Œ)
  • ์žฅ์ 2. ๊ฐ€๋ฒผ์›€ (4๋Œ€ ์ปดํฌ๋„ŒํŠธ์ฒ˜๋Ÿผ ์•ˆ๋“œ๋กœ์ด๋“œ ์‹œ์Šคํ…œ์ด ์ง์ ‘ ๊ด€๋ฆฌํ•˜์ง€ ์•Š๊ณ  ํ”„๋ž˜๊ทธ๋จผํŠธ ๋งค๋‹ˆ์ €๊ฐ€ ๊ด€๋ฆฌ)
  • ํ”„๋ž˜๊ทธ๋จผํŠธ์˜ ๋ทฐ ๊ณ„์ธต ๊ตฌ์กฐ๋Š” ํ˜ธ์ŠคํŠธ ๋ทฐ ๊ณ„์ธต ๊ตฌ์กฐ์˜ ์ผ๋ถ€๊ฐ€ ๋˜๊ฑฐ๋‚˜ ์—ฌ๊ธฐ์— ์—ฐ๊ฒฐ
  • ํƒ์ƒ‰, BottomNavigationView, ViewPager2์™€ ๊ฐ™์€ ์ผ๋ถ€ Android Jetpack ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ํ”„๋ž˜๊ทธ๋จผํŠธ์™€ ํ˜ธํ™˜

 

 

 

๐Ÿ’ก ์•กํ‹ฐ๋น„ํ‹ฐ VS ํ”„๋ž˜๊ทธ๋จผํŠธ

  • ์•กํ‹ฐ๋น„ํ‹ฐ: ์‹œ์Šคํ…œ์˜ ์•กํ‹ฐ๋น„ํ‹ฐ ๋งค๋‹ˆ์ €์—์„œ ์ธํ…ํŠธ๋ฅผ ํ•ด์„ํ•ด ์•กํ‹ฐ๋น„ํ‹ฐ๊ฐ„ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌ
  • ํ”„๋ž˜๊ทธ๋จผํŠธ: ์•กํ‹ฐ๋น„ํ‹ฐ์˜ ํ”„๋ž˜๊ทธ๋จผํŠธ ๋งค๋‹ˆ์ €์—์„œ ๋ฉ”์†Œ๋“œ๋กœ ํ”„๋ž˜๊ทธ๋จผํŠธ๊ฐ„ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌ
  • ์•กํ‹ฐ๋น„ํ‹ฐ๋กœ ํ™”๋ฉด์„ ๊ณ„์† ๋„˜๊ธฐ๋Š” ๊ฒƒ๋ณด๋‹ค, ํ”„๋ž˜๊ทธ๋จผํŠธ๋กœ ์ผ๋ถ€๋งŒ ๋ฐ”๊พธ๋Š” ๊ฒƒ์ด ์ž์› ์ด์šฉ๋Ÿ‰์ด ์ ๊ณ  ์†๋„๊ฐ€ ๋น ๋ฆ„
  • ํ”„๋ž˜๊ทธ๋จผํŠธ ์‚ฌ์šฉ์˜ ์žฅ์ 
    1. Fragment๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด Activity๋ฅผ ์ ๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Œ
      (Fragment ๊ณต๊ฐ„์— View๋งŒ ์ง‘์–ด๋„ฃ์œผ๋ฉด, ์—ฌ๋Ÿฌ Activity๋ฅผ ๋งŒ๋“ค์ง€ ์•Š์•„๋„ ์—ฌ๋Ÿฌ ํ™”๋ฉด์„ ๋ณด์—ฌ ์ค„ ์ˆ˜ ์žˆ์Œ)
    2. Acitivity์˜ ๋ณต์žก๋„๋ฅผ ์ค„์ž„
    3. ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ ˆ์ด์•„์›ƒ์„ ๋ถ„๋ฆฌํ•ด์„œ ๊ด€๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅ

 

 

 

๐Ÿ’ก ํ”„๋ž˜๊ทธ๋จผํŠธ ์ •์˜ํ•˜๊ธฐ

class FirstFragment : Fragment() {  
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_first, container, false)
    }
  • ์•กํ‹ฐ๋น„ํ‹ฐ๋ฅผ ๋งŒ๋“ค ๋•Œ์™€ ๋น„์Šทํ•˜๊ฒŒ, ํ•˜๋‚˜์˜ Kotlin ํŒŒ์ผ๊ณผ ํ•˜๋‚˜์˜ XML๋ ˆ์ด์•„์›ƒ์œผ๋กœ ์ •์˜
  • ํ”„๋ž˜๊ทธ๋จผํŠธ๋ฅผ ์ƒ์„ฑํ•˜๋ ค๋ฉด Fragment์˜ ์„œ๋ธŒํด๋ž˜์Šค(๋˜๋Š” ์ด์˜ ๊ธฐ์กด ์„œ๋ธŒํด๋ž˜์Šค)๋ฅผ ์ƒ์„ฑ
  • ํ”„๋ž˜๊ทธ๋จผํŠธ์— ๋Œ€ํ•ด ๋ ˆ์ด์•„์›ƒ์„ ์ œ๊ณตํ•˜๋ ค๋ฉด ๋ฐ˜๋“œ์‹œ onCreateView() ์ฝœ๋ฐฑ ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ (์•„๋ž˜ ์ƒ๋ช…์ฃผ๊ธฐ ์ฐธ๊ณ )
  • inflate()ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด์„œ xml ํŒŒ์ผ๋ช…์„ ์ž…๋ ฅํ•˜์—ฌ ๋ ˆ์ด์•„์›ƒ์„ ๋กœ๋“œ
  • ํ”„๋ž˜๊ทธ๋จผํŠธ๋„ ๋ถ€๋ถ„ ํ™”๋ฉด์ด๋ฏ€๋กœ ํ™”๋ฉด์— ํ‘œ์‹œ๋  ๋ทฐ๋“ค์„ ์ •์˜ํ•˜๋Š” XML ํŒŒ์ผ์„ /res/layout ํด๋” ์•ˆ์— ์ƒ์„ฑ
  • ์•ˆ๋“œ๋กœ์ด๋“œ ์ŠคํŠœ๋””์˜ค์—์„œ File > New > Fragment > Fragment(Blank)๋ฅผ ์ด์šฉํ•ด์„œ ์‰ฝ๊ฒŒ ์ƒ์„ฑ ๊ฐ€๋Šฅํ•˜๋‹ค.

 

 

 

๐Ÿ’ก ํ”„๋ž˜๊ทธ๋จผํŠธ๋ฅผ ์ •์ ์œผ๋กœ ์•กํ‹ฐ๋น„ํ‹ฐ์˜ ๋ ˆ์ด์•„์›ƒ ํŒŒ์ผ์— ์ถ”๊ฐ€ํ•˜๊ธฐ

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/fragment_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!" />
    <fragment // ๋ ˆ์ด์•„์›ƒ ํŒŒ์ผ์— ์ •์  ์ถ”๊ฐ€
        android:name="com.skmns.fragmentbasic.FirstFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/fragment" />
</LinearLayout>
  • ํ”„๋ž˜๊ทธ๋จผํŠธ๋ฅผ ์•กํ‹ฐ๋น„ํ‹ฐ์˜ ๋ ˆ์ด์•„์›ƒ ํŒŒ์ผ ์•ˆ์—์„œ ์„ ์–ธ
  • <fragment> ์•ˆ์˜ android:name ํŠน์„ฑ์€ ๋ ˆ์ด์•„์›ƒ ์•ˆ์—์„œ ์ธ์Šคํ„ด์Šคํ™”ํ•  Fragment ํด๋ž˜์Šค๋ฅผ ์ง€์ •
  • โ˜… [์ค‘์š”] ๊ฐ ํ”„๋ž˜๊ทธ๋จผํŠธ์—๋Š” ์•กํ‹ฐ๋น„ํ‹ฐ๊ฐ€ ์žฌ์‹œ์ž‘๋˜๋Š” ๊ฒฝ์šฐ ํ”„๋ž˜๊ทธ๋จผํŠธ๋ฅผ ๋ณต๊ตฌํ•˜๊ธฐ ์œ„ํ•ด ์‹œ์Šคํ…œ์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ณ ์œ ํ•œ ์‹๋ณ„์ž๊ฐ€ ํ•„์š”ํ•˜๋‹ค. ํ”„๋ž˜๊ทธ๋จผํŠธ์— ID๋ฅผ ์ œ๊ณตํ•˜๋Š” ๋ฐ์—๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์„ธ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค.
    1. ๊ณ ์œ ํ•œ ID์™€ ํ•จ๊ป˜ android:id ์†์„ฑ์„ ์ œ๊ณตํ•œ๋‹ค.
    2. ๊ณ ์œ ํ•œ ๋ฌธ์ž์—ด๊ณผ ํ•จ๊ป˜ android:tag ์†์„ฑ์„ ์ œ๊ณตํ•œ๋‹ค.
    3. ์œ„์˜ ๋‘ ๊ฐ€์ง€ ์ค‘ ์–ด๋Š ๊ฒƒ๋„ ์ œ๊ณตํ•˜์ง€ ์•Š์œผ๋ฉด, ์‹œ์Šคํ…œ์€ ์ปจํ…Œ์ด๋„ˆ ๋ทฐ์˜ ID๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

 

 

๐Ÿ’ก ํ”„๋ž˜๊ทธ๋จผํŠธ๋ฅผ ๋™์ ์œผ๋กœ ์ฝ”ํ‹€๋ฆฐ ์ฝ”๋“œ์—์„œ ์ถ”๊ฐ€ํ•˜๊ธฐ

build.gradle์— ์•„๋ž˜ ์‚ฝ์ž…

dependencies {
    val fragment_version = "1.6.2"
  	...
    implementation("androidx.fragment:fragment-ktx:$fragment_version")
}
supportFragmentManager.commit {
            replace(R.id.frameLayout, frag)
            setReorderingAllowed(true)
            addToBackStack("")
        }
  • supportFragmentManager
    ์‚ฌ์šฉ์ž ์ƒํ˜ธ์ž‘์šฉ์— ์‘๋‹ตํ•ด Fragment๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์‚ญ์ œํ•˜๋Š” ๋“ฑ์˜ ์ž‘์—…์„ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๋งค๋‹ˆ์ €
  • replace
    ์–ด๋Š ํ”„๋ ˆ์ž„ ๋ ˆ์ด์•„์›ƒ์— ๋„์šธ ๊ฒƒ์ด๋ƒ, ์–ด๋–ค ํ”„๋ž˜๊ทธ๋จผํŠธ๋ƒ ์„ค์ •
  • setReorderingAllowed
    ์• ๋‹ˆ๋ฉ”์ด์…˜๊ณผ ์ „ํ™˜์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ž‘๋™ํ•˜๋„๋ก ํŠธ๋žœ์žญ์…˜๊ณผ ๊ด€๋ จ๋œ ํ”„๋ž˜๊ทธ๋จผํŠธ์˜ ์ƒํƒœ ๋ณ€๊ฒฝ์„ ์ตœ์ ํ™”
  • addToBackStack
    ๋’ค๋กœ๊ฐ€๊ธฐ ๋ฒ„ํŠผ ํด๋ฆญ์‹œ ๋‹ค์Œ ์•ก์…˜ (์ด์ „ fragment๋กœ ๊ฐ€๊ฑฐ๋‚˜ ์•ฑ์ด ์ข…๋ฃŒ๋˜๊ฑฐ๋‚˜)

 

๐Ÿ’ก ์‚ฌ์šฉ ์˜ˆ์‹œ

๋”๋ณด๊ธฐ

0. ์ƒˆ ํ”„๋ž˜๊ทธ๋จผํŠธ ๋‘ ๊ฐœ ์ƒ์„ฑ
FirstFragment, SecondFragment

 

1. fragment_first.xml ์ˆ˜์ •

<?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"
    android:layout_width="match_parent"
    android:background="#F19B9B"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="ํ”„v๋ž˜๊ทธ๋จผํŠธ 1"
        android:textAllCaps="false"
        android:textSize="40sp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

 

 

2. fragment_second.xml ์ˆ˜์ •

<?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"
    android:layout_width="match_parent"
    android:background="#C785D3"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="ํ”„๋ž˜๊ทธ๋จผํŠธ 2"
        android:textAllCaps="false"
        android:textSize="40sp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

 

3. ์ •์ ์œผ๋กœ ์ถ”๊ฐ€
activity_main.xml ํŒŒ์ผ์„ ์—ด๊ณ , fragment๋ฅผ ํ‘œ์‹œํ•  FrameLayout๊ณผ ๋ฒ„ํŠผ 2๊ฐœ ์ถ”๊ฐ€

<?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"
    tools:context=".MainActivity">

    <FrameLayout
        android:id="@+id/frameLayout"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginStart="10dp"
        android:layout_marginEnd="10dp"
        app:layout_constraintBottom_toTopOf="@+id/fragment1_btn"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">
    </FrameLayout>

    <Button
        android:id="@+id/fragment1_btn"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:text="Frag1"
        android:textAllCaps="false"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/fragment2_btn"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/frameLayout" />

    <Button
        android:id="@+id/fragment2_btn"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:text="Frag2"
        android:textAllCaps="false"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/fragment1_btn"
        app:layout_constraintTop_toBottomOf="@+id/frameLayout" />

</androidx.constraintlayout.widget.ConstraintLayout>

 

4. MainActivity.kt์— Fragment ์ถ”๊ฐ€

MainActivity.kt ์˜ˆ์‹œ

class MainActivity : AppCompatActivity() {

    private val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(binding.root)

        binding.apply {
            fragment1Btn.setOnClickListener{
                setFragment(FirstFragment())
            }
            fragment2Btn.setOnClickListener {
                setFragment(SecondFragment())
            }
        }
        setFragment(FirstFragment())
    }

    private fun setFragment(frag : Fragment) {
        supportFragmentManager.commit {
            replace(R.id.frameLayout, frag)
            setReorderingAllowed(true)
            addToBackStack("")
        }
    }
}

 

 

 


 

 

 

2. Frament Life Cycle

 

Activity Lifecycle๊ณผ์˜ ๊ด€๊ณ„

 

ํ”„๋ž˜๊ทธ๋จผํŠธ(Fragment)๋Š” ์•ˆ๋“œ๋กœ์ด๋“œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ UI ๋ถ€๋ถ„์„ ๋ชจ๋“ˆํ™”ํ•˜์—ฌ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ๋Š” ๊ตฌ์„ฑ ์š”์†Œ์ด๋‹ค. ํ”„๋ž˜๊ทธ๋จผํŠธ๋Š” ์ž์ฒด์ ์ธ ์ƒ๋ช…์ฃผ๊ธฐ(lifecycle)๋ฅผ ๊ฐ€์ง€๋ฉฐ, ์•กํ‹ฐ๋น„ํ‹ฐ์˜ ์ƒ๋ช…์ฃผ๊ธฐ์™€ ๋ฐ€์ ‘ํ•˜๊ฒŒ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ๋‹ค. ํ”„๋ž˜๊ทธ๋จผํŠธ์˜ ์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์€ ์•ˆ๋“œ๋กœ์ด๋“œ ์•ฑ์„ ํšจ์œจ์ ์œผ๋กœ ๊ด€๋ฆฌํ•˜๊ณ , ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ถ€๋“œ๋Ÿฌ์šด ์ธํ„ฐํŽ˜์ด์Šค ๊ฒฝํ—˜์„ ์ œ๊ณตํ•˜๋Š” ๋ฐ ์ค‘์š”ํ•˜๋‹ค. ๋”ฐ๋ผ์„œ ํ”„๋ž˜๊ทธ๋จผํŠธ ์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ์ดํ•ดํ•˜๊ณ , ๋ฉ”๋ชจ๋ฆฌ ๋ฆญ(๋ˆ„์ˆ˜)์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š๋„๋ก ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜์ž.

 

 

onAttach()

  • ํ”„๋ž˜๊ทธ๋จผํŠธ๊ฐ€ ์•กํ‹ฐ๋น„ํ‹ฐ์— ์—ฐ๊ฒฐ๋  ๋•Œ ํ˜ธ์ถœ
  • ์ด ์‹œ์ ์—์„œ ํ”„๋ž˜๊ทธ๋จผํŠธ๋Š” ์•กํ‹ฐ๋น„ํ‹ฐ์™€ ์•„์ง ์™„์ „ํžˆ ์—ฐ๊ฒฐ๋˜์ง€๋Š” ์•Š์Œ

 

onCreate()

  • Fragment๊ฐ€ ์ƒ์„ฑ(CREATED) ๋œ ์ƒํ™ฉ
  • ์ด ์‹œ์ ์—๋Š” ์•„์ง Fragment View ๊ฐ€ ์ƒ์„ฑ๋˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— Fragment ์˜ View ์™€ ๊ด€๋ จ๋œ ์ž‘์—…์„ ๋‘๋ฉด ์•ˆ ๋จ
  • onCreate() ์ฝœ๋ฐฑ ์‹œ์ ์—๋Š” Bundle ํƒ€์ž…์œผ๋กœ savedInstanceState ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ํ•จ๊ป˜ ์ œ๊ณต๋˜๋Š”๋ฐ, ์ด๋Š” onSaveInstanceState() ์ฝœ๋ฐฑ ํ•จ์ˆ˜์— ์˜ํ•ด ์ €์žฅ๋œ Bundle ๊ฐ’
  • savedInstanceState ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” ํ”„๋ž˜๊ทธ๋จผํŠธ๊ฐ€ ์ฒ˜์Œ ์ƒ์„ฑ ๋์„ ๋•Œ๋งŒ null ๋กœ ๋„˜์–ด์˜ค๋ฉฐ, onSaveInstanceState() ํ•จ์ˆ˜๋ฅผ ์žฌ์ •์˜ํ•˜์ง€ ์•Š์•˜๋”๋ผ๋„ ๊ทธ ์ดํ›„ ์žฌ์ƒ์„ฑ๋ถ€ํ„ฐ๋Š” non-null ๊ฐ’์œผ๋กœ ๋„˜์–ด ์˜ด
  • ์ดˆ๊ธฐํ™” ์ž‘์—…, ๋ฆฌ์†Œ์Šค ๋ฐ”์ธ๋”ฉ ๋“ฑ์„ ์ˆ˜ํ–‰

 

onCreateView(), onViewCreated()

  • ํ”„๋ž˜๊ทธ๋จผํŠธ์˜ ๋ ˆ์ด์•„์›ƒ์„ ์ธํ”Œ๋ ˆ์ดํŠธํ•˜๋Š” ๊ณณ
  • onCreateView()์˜ ๋ฐ˜ํ™˜๊ฐ’์œผ๋กœ ์ •์ƒ์ ์ธ Fragment View ๊ฐ์ฒด๋ฅผ ์ œ๊ณตํ–ˆ์„ ๋•Œ๋งŒ Fragment View ์˜ Lifecycle ์ƒ์„ฑ
  • onCreateView()๋ฅผ ์žฌ์ •์˜ ํ•˜์—ฌ Fragment View๋ฅผ ์ง์ ‘ ์ƒ์„ฑํ•˜๊ณ  inflate ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, LayoutId๋ฅผ ๋ฐ›๋Š” Fragment์˜ ์ƒ์„ฑ์ž๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๋‹น ๋ฆฌ์†Œ์Šค ์•„์ด๋”” ๊ฐ’์„ ํ†ตํ•ด onCreateView() ์žฌ์ •์˜ ์—†์ด๋„ Fragment View ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Œ
  • onCreateView() ๋ฅผ ํ†ตํ•ด ๋ฐ˜ํ™˜๋œ View ๊ฐ์ฒด๋Š” onViewCreated() ์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ „๋‹ฌ
  • ํ•ด๋‹น ์‹œ์ ์—์„  Fragment View์˜ Lifecycle ์ด INITIALIZED ์ƒํƒœ๋กœ ์—…๋ฐ์ดํŠธ
  • ๋ทฐ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๋ ˆ์ด์•„์›ƒ์„ ์„ค์ •
    onViewCreated()์—์„  View ์ดˆ๊ธฐ๊ฐ’ ์„ค์ •, LiveData ์˜ต์ €๋น™, RecyclerView/ViewPager2 ์— ์‚ฌ์šฉ๋  Adapter ์„ธํŒ… ๋“ฑ

 

onViewStateRestored()

  • ์ €์žฅํ•ด๋‘” ๋ชจ๋“  state ๊ฐ’์ด Fragment์˜ View ๊ณ„์ธต๊ตฌ์กฐ์— ๋ณต์› ๋์„ ๋•Œ ํ˜ธ์ถœ
  • ์—ฌ๊ธฐ์„œ๋ถ€ํ„ฐ๋Š” ์ฒดํฌ๋ฐ•์Šค ์œ„์ ฏ์ด ํ˜„์žฌ ์ฒดํฌ ๋˜์–ด์žˆ๋Š”์ง€ ๋“ฑ ๊ฐ ๋ทฐ์˜ ์ƒํƒœ๊ฐ’์„ ์ฒดํฌํ•  ์ˆ˜ ์žˆ์Œ
  • View lifecycle owner ๋Š” ์ด๋•Œ INITIALIZED ์ƒํƒœ์—์„œ CREATED ์ƒํƒœ๋กœ ๋ณ€๊ฒฝ

 

onStart()

  • Fragment๊ฐ€ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ณด์—ฌ์งˆ ์ค€๋น„๊ฐ€ ๋˜์—ˆ์„ ๋•Œ ํ˜ธ์ถœ
  • ์ฃผ๋กœ Fragment๊ฐ€ attach๋˜์–ด์žˆ๋Š” Activity์˜ onStart() ์‹œ์ ๊ณผ ์œ ์‚ฌ
  • ์ด ์‹œ์ ๋ถ€ํ„ฐ๋Š” Fragment์˜ child FragmentManager๋ฅผ ํ†ตํ•ด FragmentTransaction์„ ์•ˆ์ „ํ•˜๊ฒŒ ์ˆ˜ํ–‰
  • Fragment View ์˜ Lifecycle ๋˜ํ•œ STARTED๋กœ ๋ณ€๊ฒฝ
  • ํ•„์š”ํ•œ ๋ฆฌ์†Œ์Šค๋ฅผ ํ• ๋‹นํ•˜๊ฑฐ๋‚˜, ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์‹œ์ž‘

 

onResume()

  • ๋ชจ๋“  Animator์™€ Transitionํšจ๊ณผ๊ฐ€ ์ข…๋ฃŒ๋˜๊ณ , ํ”„๋ž˜๊ทธ๋จผํŠธ๊ฐ€ ์‚ฌ์šฉ์ž์™€ ์ƒํ˜ธ์ž‘์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ƒํƒœ๊ฐ€ ๋˜์—ˆ์„ ๋•Œ ํ˜ธ์ถœ
  • ์ฃผ๋กœ Fragment๊ฐ€ attach๋˜์–ด์žˆ๋Š” Activity์˜ onResume() ์‹œ์ ๊ณผ ์œ ์‚ฌ
  • ์‚ฌ์šฉ์ž๊ฐ€ ํ”„๋ž˜๊ทธ๋จผํŠธ์™€ ์ƒํ˜ธ์ž‘์šฉ ํ•˜๊ธฐ์— ์ ์ ˆํ•œ ์ƒํƒœ
  • ๋ฐ˜๋Œ€๋กœ onResume() ์ด ํ˜ธ์ถœ๋˜์ง€ ์•Š์€ ์‹œ์ ์—์„œ๋Š” ์ž…๋ ฅ์„ ์‹œ๋„ํ•˜๊ฑฐ๋‚˜ ํฌ์ปค์Šค๋ฅผ ์„ค์ •ํ•˜๋Š” ๋“ฑ์˜ ์ž‘์—… ์•ˆ ๋จ
  • ํ”„๋ž˜๊ทธ๋จผํŠธ๊ฐ€ ํฌ๊ทธ๋ผ์šด๋“œ์— ์žˆ์„ ๋•Œ ์‹คํ–‰๋˜๋Š” ์ž‘์—…์„ ์—ฌ๊ธฐ์„œ ์ฒ˜๋ฆฌ

 

onPause()

  • ํ”„๋ž˜๊ทธ๋จผํŠธ๊ฐ€ ์ผ์‹œ์ •์ง€๋  ๋•Œ ํ˜ธ์ถœ
  • ์‚ฌ์šฉ์ž๊ฐ€ Fragment ๋ฅผ ๋– ๋‚˜๊ธฐ ์‹œ์ž‘ํ–ˆ์ง€๋งŒ Fragment๋Š” ์—ฌ์ „ํžˆ visible ์ผ ๋•Œ ํ˜ธ์ถœ
  • Fragment์™€ View ์˜ Lifecycle์ด PAUSED ๊ฐ€ ์•„๋‹Œ STARTED๊ฐ€ ๋จ
    (์—„๋ฐ€ํžˆ ๋”ฐ์ง€๋ฉด Lifecycle ์— PAUSE ์™€ STOP ์— ํ•ด๋‹นํ•˜๋Š” ์ƒํƒœ๊ฐ€ ์—†์Œ)

 

onStop()

  • Fragment๊ฐ€ ๋”์ด์ƒ ํ™”๋ฉด์— ๋ณด์—ฌ์ง€์ง€ ์•Š๊ฒŒ ๋  ๋•Œ ํ˜ธ์ถœ
  • ๋ถ€๋ชจ ์•กํ‹ฐ๋น„ํ‹ฐ๋‚˜ ํ”„๋ž˜๊ทธ๋จผํŠธ๊ฐ€ ์ค‘๋‹จ๋์„ ๋•Œ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ, ๋ถ€๋ชจ ์•กํ‹ฐ๋น„ํ‹ฐ๋‚˜ ํ”„๋ž˜๊ทธ๋จผํŠธ์˜ ์ƒํƒœ๊ฐ€ ์ €์žฅ๋  ๋•Œ๋„ ํ˜ธ์ถœ
  • Fragment ์™€ View ์˜ Lifecycle ์€ CREATED ์ƒํƒœ๊ฐ€ ๋จ
  • API 28 ๋ฒ„์ „์„ ๊ธฐ์ ์œผ๋กœ ํ•จ์ˆ˜ ํ˜ธ์ถœ ์ˆœ์„œ
    ON_STOP Event -> onStop() -> (์ƒํƒœ ์ €์žฅ) -> onSaveInstanceState()

 

 onDestroyView()

  • ํ”„๋ž˜๊ทธ๋จผํŠธ์˜ ๋ทฐ์™€ ๊ด€๋ จ๋œ ๋ฆฌ์†Œ์Šค๋ฅผ ์ •๋ฆฌํ•  ๋•Œ ํ˜ธ์ถœ
  • ๋ชจ๋“  exit animation ๊ณผ transition ์ด ์™„๋ฃŒ๋˜๊ณ , Fragment๊ฐ€ ํ™”๋ฉด์œผ๋กœ๋ถ€ํ„ฐ ๋ฒ—์–ด๋‚ฌ์„ ๊ฒฝ์šฐ ํ˜ธ์ถœ
  • Fragment View ์˜ Lifecycle ์€ DESTROYED ์ƒํƒœ๊ฐ€ ๋จ
  • ์ด ์‹œ์ ๋ถ€ํ„ฐ๋Š” getViewLifecycleOwnerLiveData() ์˜ ๋ฆฌํ„ด๊ฐ’์œผ๋กœ null ์ด ๋ฐ˜ํ™˜
  • ์ด ์‹œ์ ๋ถ€ํ„ฐ๋Š” ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰ํ„ฐ์— ์˜ํ•ด ์ˆ˜๊ฑฐ๋  ์ˆ˜ ์žˆ๋„๋ก Fragment View์— ๋Œ€ํ•œ ๋ชจ๋“  ์ฐธ์กฐ๊ฐ€ ์ œ๊ฑฐ๋˜์–ด์•ผ ํ•จ
    (์•„์ง ํ”„๋ž˜๊ทธ๋จผํŠธ ์ž์ฒด๋Š” ๋ฉ”๋ชจ๋ฆฌ์— ๋‚จ์•„์žˆ์œผ๋ฏ€๋กœ, ํ”„๋ž˜๊ทธ๋จผํŠธ ๋ทฐ์— ๋Œ€ํ•œ ๋ชจ๋“  ์ฐธ์กฐ๋ฅผ ์ œ๊ฑฐํ•ด์•ผ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ๋ฐฉ์ง€)

 

onDestroy()

  • Fragment ๊ฐ€ ์ œ๊ฑฐ๋˜๊ฑฐ๋‚˜ FragmentManager ๊ฐ€ destroy ๋์„ ๊ฒฝ์šฐ ํ˜ธ์ถœ
  • ํ”„๋ž˜๊ทธ๋จผํŠธ์˜ Lifecycle ์€ DESTROYED ์ƒํƒœ๋กœ ๋ณ€๊ฒฝ
  • ํ”„๋ž˜๊ทธ๋จผํŠธ์˜ ์ƒํƒœ๋ฅผ ์ •๋ฆฌํ•˜๊ณ , ๋ชจ๋“  ๋ฆฌ์†Œ์Šค๋ฅผ ํ•ด์ œ

 

onDetach()

  • ํ”„๋ž˜๊ทธ๋จผํŠธ๊ฐ€ ์•กํ‹ฐ๋น„ํ‹ฐ๋กœ๋ถ€ํ„ฐ ๋ถ„๋ฆฌ๋  ๋•Œ ํ˜ธ์ถœ
  • ํ”„๋ž˜๊ทธ๋จผํŠธ๊ฐ€ ์•กํ‹ฐ๋น„ํ‹ฐ์™€์˜ ๋ชจ๋“  ์—ฐ๊ฒฐ์„ ํ•ด์ œ

 

 


 

3. Fragment ๋ฐ์ดํ„ฐ ์ „๋‹ฌ ๋ฐฉ์‹

 

  • ํ”„๋ž˜๊ทธ๋จผํŠธ ๊ฐ„์˜ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ์€ ์•ˆ๋“œ๋กœ์ด๋“œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์œ ์—ฐ์„ฑ๊ณผ ๋ชจ๋“ˆ์„ฑ์„ ํ–ฅ์ƒ์‹œํ‚ค๋Š” ์ค‘์š”ํ•œ ๊ธฐ๋Šฅ

 

 

1. Activity → Fragment

  • ์•กํ‹ฐ๋น„ํ‹ฐ์—์„œ ํ”„๋ž˜๊ทธ๋จผํŠธ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•  ๋•Œ
  • ํ”„๋ž˜๊ทธ๋จผํŠธ์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ  newInstance ๋ฉ”์†Œ๋“œ๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌ
  • Bundle ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ํ”„๋ž˜๊ทธ๋จผํŠธ์˜ ์ธ์ž(arguments)๋กœ ์„ค์ •ํ•˜๊ณ , ์ด ์ธ์ž๋ฅผ ํ”„๋ž˜๊ทธ๋จผํŠธ๊ฐ€ ๋ฐ›์•„ ์‚ฌ์šฉ

 

MainActivity.kt (๋ณด๋‚ด๋Š” ์ฝ”๋“œ)

binding.run {
            fragment1Btn.setOnClickListener{
                val dataToSend = "Hello First Fragment! \n From Activity"
                val fragment = FirstFragment.newInstance(dataToSend)
                setFragment(fragment)
            }

            fragment2Btn.setOnClickListener {
                val dataToSend = "Hello Second Fragment!\n From Activity"
                val fragment = SecondFragment.newInstance(dataToSend)
                setFragment(fragment)
            }
  • Fragment1Btn ํด๋ฆญ ๋ฆฌ์Šค๋„ˆ ์•ˆ์—์„œ FirstFragment์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ ,
    newInstance ๋ฉ”์†Œ๋“œ์— ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•˜์—ฌ ํ”„๋ž˜๊ทธ๋จผํŠธ๋ฅผ ์„ค์ •(set)
  • Fragment2Btn์— ๋Œ€ํ•ด์„œ๋„ ๋™์ผํ•œ ๋ฐฉ๋ฒ•์œผ๋กœ SecondFragment์— ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌ

 

FirstFragment.kt (๋ฐ›๋Š” ์ฝ”๋“œ):

private var param1: String? = null

companion object {
        @JvmStatic
        fun newInstance(param1: String) =
            // [1] Activity -> FirstFragment
            FirstFragment().apply {
                arguments = Bundle().apply {
                    putString(ARG_PARAM1, param1)
                }
            }
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        // [1] Activity -> FirstFragment
        binding.tvFrag1Text.text = param1     
}
  • newInstance ๋ฉ”์†Œ๋“œ์—์„œ ์ „๋‹ฌ๋ฐ›์€ ๋ฐ์ดํ„ฐ๋ฅผ Bundle์— ๋‹ด๊ณ , ํ”„๋ž˜๊ทธ๋จผํŠธ์˜ ์ธ์ž๋กœ ์„ค์ •
  • onViewCreated์—์„œ๋Š” ์ธ์ž๋กœ ๋ฐ›์€ ๋ฐ์ดํ„ฐ๋ฅผ ํ…์ŠคํŠธ ๋ทฐ์— ์„ค์ •

 

 

2. Fragment → Fragment

  • ํ•œ ํ”„๋ž˜๊ทธ๋จผํŠธ์—์„œ ๋‹ค๋ฅธ ํ”„๋ž˜๊ทธ๋จผํŠธ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•  ๋•Œ
  • ์ฒซ ๋ฒˆ์งธ ํ”„๋ž˜๊ทธ๋จผํŠธ์—์„œ ๋‘ ๋ฒˆ์งธ ํ”„๋ž˜๊ทธ๋จผํŠธ์˜ newInstance ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑ, ๋ฐ์ดํ„ฐ ์ „๋‹ฌ

 

FirstFragment.kt (๋ณด๋‚ด๋Š” ์ฝ”๋“œ)

        binding.btnGofrag2.setOnClickListener{
            val dataToSend = "Hello Fragment2! \n From Fragment1"
            val fragment2 = SecondFragment.newInstance(dataToSend)
            requireActivity().supportFragmentManager.beginTransaction()
                .replace(R.id.frameLayout, fragment2)
                .addToBackStack(null)
                .commit()
        }
  • ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ SecondFragment์˜ ์ƒˆ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑ
  • newInstance ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•œ ํ›„ ํ”„๋ž˜๊ทธ๋จผํŠธ ํŠธ๋žœ์žญ์…˜์„ ํ†ตํ•ด ๋‘ ๋ฒˆ์งธ ํ”„๋ž˜๊ทธ๋จผํŠธ๋ฅผ ์‹œ์ž‘

 

SecondFragment.kt (๋ฐ›๋Š” ์ฝ”๋“œ)

๋”๋ณด๊ธฐ
private const val ARG_PARAM1 = "param1"

class SecondFragment : Fragment() {

    private var param1: String? = null

    private var _binding: FragmentSecondBinding? = null
    private val binding get() = _binding!!


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        arguments?.let {
            param1 = it.getString(ARG_PARAM1)
        }
    }

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

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        binding.tvFrag2Text.text = param1
    }


    companion object {
        @JvmStatic
        fun newInstance(param1: String) =
            // [1] Activity -> FirstFragment
            SecondFragment().apply {
                arguments = Bundle().apply {
                    putString(ARG_PARAM1, param1)
                }
            }
    }

    override fun onDestroyView() {
        super.onDestroyView()
        // Binding ๊ฐ์ฒด ํ•ด์ œ
        _binding = null
    }
}
  • newInstance ๋ฉ”์†Œ๋“œ๋กœ ์ „๋‹ฌ๋ฐ›์€ ๋ฐ์ดํ„ฐ๋ฅผ Bundle์— ๋‹ด๊ณ , onCreate ๋˜๋Š” onViewCreated์—์„œ Bundle๋กœ๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ๋ฅผ ์ถ”์ถœํ•˜์—ฌ ์‚ฌ์šฉ

 

 

 

3. Fragment → Activity

  • ํ”„๋ž˜๊ทธ๋จผํŠธ์—์„œ ์•กํ‹ฐ๋น„ํ‹ฐ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•  ๋•Œ
  • ์ฝœ๋ฐฑ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ •์˜ํ•˜๊ณ , ํ•ด๋‹น ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์•กํ‹ฐ๋น„ํ‹ฐ๊ฐ€ ๊ตฌํ˜„ํ•˜๋„๋ก ํ•จ
  • ํ”„๋ž˜๊ทธ๋จผํŠธ๋Š” ์ด ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์•กํ‹ฐ๋น„ํ‹ฐ์— ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌ

 

SecondFragment.kt (๋ณด๋‚ด๋Š” ์ฝ”๋“œ):

๋”๋ณด๊ธฐ
private const val ARG_PARAM1 = "param1"

interface FragmentDataListener {
    fun onDataReceived(data: String)
}

class SecondFragment : Fragment() {

    private var listener: FragmentDataListener? = null

    private var param1: String? = null

    private var _binding: FragmentSecondBinding? = null
    private val binding get() = _binding!!


    override fun onAttach(context: Context) {
        super.onAttach(context)

        if (context is FragmentDataListener) {
            listener = context
        } else {
            throw RuntimeException("$context must implement FragmentDataListener")
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        arguments?.let {
            param1 = it.getString(ARG_PARAM1)
        }
    }

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

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        binding.tvFrag2Text.text = param1

        binding.btnSendActivity.setOnClickListener{
            val dataToSend = "Hello from SecondFragment!"
            listener?.onDataReceived(dataToSend)
        }
    }


    companion object {
        @JvmStatic
        fun newInstance(param1: String) =
            // [1] Activity -> FirstFragment
            SecondFragment().apply {
                arguments = Bundle().apply {
                    putString(ARG_PARAM1, param1)
                }
            }
    }

    override fun onDestroyView() {
        super.onDestroyView()
        // Binding ๊ฐ์ฒด ํ•ด์ œ
        _binding = null
        listener = null
    }
}
  • FragmentDataListener ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ •์˜ํ•˜๊ณ , ํ”„๋ž˜๊ทธ๋จผํŠธ๊ฐ€ ์•กํ‹ฐ๋น„ํ‹ฐ์— ๋ถ™์„ ๋•Œ (onAttach)
    ์•กํ‹ฐ๋น„ํ‹ฐ๊ฐ€ ์ด ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ–ˆ๋Š”์ง€ ํ™•์ธ
  • ๋ฒ„ํŠผ ํด๋ฆญ ๋ฆฌ์Šค๋„ˆ์—์„œ onDataReceived ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ์•กํ‹ฐ๋น„ํ‹ฐ์— ์ „๋‹ฌ

 

MainActivity.kt (๋ฐ›๋Š” ์ฝ”๋“œ):

๋”๋ณด๊ธฐ
class MainActivity : AppCompatActivity(), FragmentDataListener {

    private val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(binding.root)

        binding.run {
            fragment1Btn.setOnClickListener{
                // [1] Activity -> FirstFragment
                val dataToSend = "Hello First Fragment! \n From Activity"
                val fragment = FirstFragment.newInstance(dataToSend)
                setFragment(fragment)
            }

            fragment2Btn.setOnClickListener {
                // [1] Activity -> SecondFragment
                val dataToSend = "Hello Second Fragment!\n From Activity"
                val fragment = SecondFragment.newInstance(dataToSend)
                setFragment(fragment)
            }
        }

        setFragment(FirstFragment())
    }

    private fun setFragment(frag : Fragment) {
        supportFragmentManager.commit {
            replace(R.id.frameLayout, frag)
            setReorderingAllowed(true)
            addToBackStack("")
        }
    }

    // [3] SecondFragment -> Activity
    override fun onDataReceived(data: String) {
        // Fragment์—์„œ ๋ฐ›์€ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌ
        Toast.makeText(this, data, Toast.LENGTH_SHORT).show()
    }
}
  •  MainActivity๋Š” FragmentDataListener ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ ,
    onDataReceived ๋ฉ”์†Œ๋“œ๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋“œํ•˜์—ฌ ํ”„๋ž˜๊ทธ๋จผํŠธ๋กœ๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์Œ
  • ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์œผ๋ฉด Toast ๋ฉ”์‹œ์ง€๋กœ ํ‘œ์‹œ

 


 

4. Fragment ๋ฐ์ดํ„ฐ ์ „๋‹ฌ ๋ฐฉ์‹ (์‹ฌํ™”)

 

  1. FragmentManager์— Bundle๋กœ Date๋ฅผ ๋‹ด์•„ ์ „๋‹ฌ
  2. Fragment Result API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Data ์ „๋‹ฌ
  3. Fragment๊ฐ„ ๊ณตํ†ต์˜ ViewModel(ex. HostActivity์˜ ViewModel)๋กœ ์ „๋‹ฌ
  4. Jetpack์˜ Navigation์—์„œ ์ œ๊ณตํ•˜๋Š” safe-args๋กœ ์ „๋‹ฌ

๊ฐ๊ฐ์˜ ๋ฐฉ๋ฒ•์— ์žฅ๋‹จ์ ์ด ์žˆ์œผ๋ฉฐ ์ƒํ™ฉ์— ๋”ฐ๋ผ ์ ํ•ฉํ•œ ๋ฐฉ๋ฒ• ์‚ฌ์šฉ

 

 

FragmentManager์— Bundle๋กœ Data๋ฅผ ๋‹ด์•„ ์ „๋‹ฌ

  • FragmentManager๋Š” Android์—์„œ Fragment๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ์‹œ์Šคํ…œ ์„œ๋น„์Šค
  • ์ด ๋ฐฉ๋ฒ•์€ Fragment ๊ฐ„์— ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๊ฐ€์žฅ ์ง์ ‘์ ์ด๊ณ  ๊ธฐ๋ณธ์ ์ธ ๋ฐฉ๋ฒ• ์ค‘ ํ•˜๋‚˜
  • ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•  Fragment์— Bundle์„ ์ƒ์„ฑํ•˜๊ณ , ๊ทธ ์•ˆ์— ์ „๋‹ฌํ•˜๋ ค๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ด์Œ
  • ๊ทธ ํ›„์— setArguments() ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Bundle์„ ์ „๋‹ฌํ•˜๋ ค๋Š” Fragment์— ์„ค์ •
  • ์ „๋‹ฌ๋ฐ›๋Š” Fragment์—์„œ๋Š” getArguments() ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Bundle์„ ๋ฐ›๊ณ , ๊ทธ ์•ˆ์— ๋‹ด๊ธด ๋ฐ์ดํ„ฐ๋ฅผ ์ถ”์ถœํ•˜์—ฌ ์‚ฌ์šฉ
  • ๊ฐ„๋‹จํ•˜๊ณ  ์ง๊ด€์ ์ธ ๋ฐฉ๋ฒ•์ด์ง€๋งŒ, ๋ฐ์ดํ„ฐ์˜ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋‚˜ ๋ณต์žกํ•œ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ์—๋Š” ์ ํ•ฉํ•˜์ง€ ์•Š์Œ

 

Fragment Result API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Data ์ „๋‹ฌ

  • Fragment Result API๋Š” Jetpack ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ํฌํ•จ๋œ ๊ธฐ๋Šฅ์œผ๋กœ, Fragment ๊ฐ„์— ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ ๋ฐ›๋Š” ๋ฐ ์‚ฌ์šฉ
  • ์ด ๋ฐฉ๋ฒ•์€ Fragment ๊ฐ„์— ์š”์ฒญ๊ณผ ๊ฒฐ๊ณผ๋ฅผ ์ฃผ๊ณ ๋ฐ›๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ์ œ๊ณต
  • ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญํ•˜๋Š” Fragment์—์„œ๋Š” startActivityForResult() ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›์„ Fragment๋ฅผ ํ˜ธ์ถœ
  • ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›๋Š” Fragment์—์„œ๋Š” setResult() ๋ฉ”์„œ๋“œ๋กœ ๊ฒฐ๊ณผ๋ฅผ ์„ค์ •, onActivityResult() ๋ฉ”์„œ๋“œ๋กœ ๊ฒฐ๊ณผ๋ฅผ ์ฒ˜๋ฆฌ
  • requestKey๋Š” ์‚ฌ์šฉํ•˜๋Š” Fragment์—์„œ ์–ด๋–ค listener์—๊ฒŒ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•  ์ง€ ๊ฒฐ์ •ํ•˜๊ธฐ ์œ„ํ•œ ์‹๋ณ„์ž๋กœ ์‚ฌ์šฉ
  • Fragment ๊ฐ„์˜ ๋น„๋™๊ธฐ์ ์ธ ๋ฐ์ดํ„ฐ ๊ตํ™˜์„ ํšจ์œจ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•

 

Fragment๊ฐ„ ๊ณตํ†ต์˜ ViewModel(ex. HostActivity์˜ ViewModel)๋กœ ์ „๋‹ฌ

  • ViewModel์€ ์•ˆ๋“œ๋กœ์ด๋“œ ์•„ํ‚คํ…์ฒ˜ ์ปดํฌ๋„ŒํŠธ ์ค‘ ํ•˜๋‚˜๋กœ, ๋ฐ์ดํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ  UI์™€ ๊ด€๋ จ๋œ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ์ฒ˜๋ฆฌ
  • Fragment๋“ค์ด ๊ณต์œ ํ•˜๋Š” ViewModel์„ ์ƒ์„ฑํ•˜์—ฌ ๊ทธ ์•ˆ์— ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๊ณ  ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•
  • Fragment๋“ค์€ ํ•ด๋‹น ViewModel์„ ์ฐธ์กฐํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๊ฑฐ๋‚˜ ์“ธ ์ˆ˜ ์žˆ์Œ
    (ViewModel์€ Activity์˜ lifecycle๋ณด๋‹ค ์˜ค๋ž˜ ์‚ด์•„์žˆ๋Š” ๊ฒƒ์ด ๋ณด์žฅ๋˜๊ธฐ ๋•Œ๋ฌธ์—,
    ์•ˆ์ „ํ•˜๊ฒŒ ๊ณตํ†ต์˜ Activity์˜ ViewModel์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ์ด ๊ฐ€๋Šฅ)
  • ์—ฌ๋Ÿฌ Fragment ๊ฐ„์— ๋ฐ์ดํ„ฐ๋ฅผ ๊ณต์œ ํ•˜๊ณ  ์œ ์ง€ํ•˜๊ธฐ ์šฉ์ดํ•˜๋ฉฐ, ๋ฐ์ดํ„ฐ์˜ ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋˜๋Š” ๋ฐฉ๋ฒ•

 

Jetpack์˜ Navigation์—์„œ ์ œ๊ณตํ•˜๋Š” safe-args๋กœ ์ „๋‹ฌ

  • Jetpack์˜ Navigation์€ Android ์•ฑ์—์„œ ํ™”๋ฉด ๊ฐ„์˜ ์ด๋™์„ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ
  • safe-args๋Š” Navigation ๊ทธ๋ž˜ํ”„์—์„œ ๋ชฉ์ ์ง€ ๊ฐ„์— ์•ˆ์ „ํ•˜๊ฒŒ ์ธ์ž๋ฅผ ์ „๋‹ฌํ•˜๊ธฐ ์œ„ํ•œ ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ์ œ๊ณต
  • Navigation ๊ทธ๋ž˜ํ”„์—์„œ ๊ฐ ๋ชฉ์ ์ง€์— ํ•„์š”ํ•œ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ •์˜, safe-args ํ”Œ๋Ÿฌ๊ทธ์ธ์€ ์ด๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์ฝ”๋“œ ์ž๋™ ์ƒ์„ฑ
  • ์ปดํŒŒ์ผ ํƒ€์ž„์— ์•ˆ์ „์„ฑ์„ ๋ณด์žฅํ•˜๊ณ ,๋ช…์‹œ์ ์œผ๋กœ ์ •์˜๋œ ์ธ์ž๋ฅผ ํ†ตํ•ด ๋ชฉ์ ์ง€ ๊ฐ„์˜ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ์„ ๊ฐ„๋‹จํ•˜๊ณ  ์•ˆ์ „ํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•
  • Jetpack์˜ Navigation์„ ์‚ฌ์šฉํ•˜๋Š” ํ”„๋กœ์ ํŠธ์—์„œ ์ ์šฉํ•˜๋Š” ๊ฒƒ์„ ์ถ”์ฒœ

 

 

 

์ฐธ๊ณ  ๋ธ”๋กœ๊ทธ1 (๋งํฌ)
์ฐธ๊ณ  ๋ธ”๋กœ๊ทธ2 (๋งํฌ)

 

 

 

 

 

 

๋ฐ˜์‘ํ˜•
 ๐Ÿ’ฌ C O M M E N T