๊นจ์•Œ ๊ฐœ๋… ๐Ÿ“‘/Android

[Android] Fragment์˜ ์ƒ๋ช…์ฃผ๊ธฐ

interfacer_han 2024. 1. 24. 12:28

#1 ์ด์ „ ๊ธ€

[Android] Activity์˜ ์ƒ๋ช…์ฃผ๊ธฐ

#1 Android Application์˜ ์‹œ์ž‘ (AndroidManifext.xml) ... ์šฐ๋ฆฌ๊ฐ€ ์•ฑ ์•„์ด์ฝ˜์„ ๋ˆ„๋ฅด๋ฉด, ์•ˆ๋“œ๋กœ์ด๋“œ ์‹œ์Šคํ…œ์€ ํ•ด๋‹น ์•ฑ์˜ Launcher Activity๋ฅผ ์‹คํ–‰์‹œํ‚จ๋‹ค. AndroidManifext.xml์˜ ๋“ฑ๋ก๋œ ์•กํ‹ฐ๋น„ํ‹ฐ ์ค‘์—์„œ ํƒœ๊ทธ๋ฅผ ๊ฐ€์ง€๊ณ 

kenel.tistory.com

ํ”„๋ž˜๊ทธ๋จผํŠธ๋Š” ์•กํ‹ฐ๋น„ํ‹ฐ์™€ ๋น„์Šทํ•˜์ง€๋งŒ, ๊ฐ€์žฅ ์ฃผ์š”ํ•œ ์ฐจ์ด์ ์€ ํ™€๋กœ ์„ค ์ˆ˜ ์—†์œผ๋ฉฐ ๋ฐ˜๋“œ์‹œ ์•กํ‹ฐ๋น„ํ‹ฐ๋‚˜ ๋˜ ๋‹ค๋ฅธ ํ”„๋ž˜๊ทธ๋จผํŠธ์— ์ข…์†๋˜์–ด ๋™์ž‘ํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ํ”„๋ž˜๊ทธ๋จผํŠธ๋Š” ์•กํ‹ฐ๋น„ํ‹ฐ์ฒ˜๋Ÿผ ์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ๊ฐ€์ง€๋ฉฐ, ์ข…์†๋œ ์•กํ‹ฐ๋น„ํ‹ฐ๋‚˜ ๋˜ ๋‹ค๋ฅธ ํ”„๋ž˜๊ทธ๋จผํŠธ์˜ ์ƒ๋ช…์ฃผ๊ธฐ์— ์˜ํ–ฅ์„ ๋ฐ›๊ธฐ๋„ ํ•œ๋‹ค. ์ด์ „ ๊ธ€์— ์ด์–ด ์ด๋ฒˆ์—๋Š” Fragment์˜ ์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ์‚ดํŽด๋ณธ๋‹ค. 
 

#2 Fragment์˜ ์ƒ๋ช…์ฃผ๊ธฐ ํ๋ฆ„๋„

๊ฐ ์ƒ๋ช…์ฃผ๊ธฐ์— ํ•ด๋‹นํ•˜๋Š” ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋“ค์˜ ์—ญํ• ์€ Activity์—์„œ์™€ ๊ฑฐ์˜ ๋น„์Šทํ•˜๋‹ค. ์„ค๋ช…๋ณด๋‹ค๋Š” ์‹ค์ œ ์•ฑ์„ ํ†ตํ•ด ๊ฐ์„ ์žก๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. ์ด์ „ ๊ธ€์—์„œ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ, ์ƒ๋ช…์ฃผ๊ธฐ์— ๋”ฐ๋ฅธ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋“ค์— Log๋ฅผ ๋‹ฌ์•„ ์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ์‚ดํŽด๋ณผ ์ˆ˜ ์žˆ๋Š” ์•ฑ์„ ๋งŒ๋“ค์–ด๋ณด์•˜๋‹ค.
 

#3 ํ”„๋ž˜๊ทธ๋จผํŠธ ์ƒ๋ช…์ฃผ๊ธฐ ์‚ดํŽด๋ณด๊ธฐ์šฉ ์•ฑ

#3-1 ๊ฐœ์š”

์•กํ‹ฐ๋น„ํ‹ฐ 2๊ฐœ(MainActivity, SecondActivity)๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ๊ฐ๊ฐ์˜ ์•กํ‹ฐ๋น„ํ‹ฐ๋Š” ๋ฐ”ํ…€ ๋‚ด๋น„๊ฒŒ์ด์…˜ ๋ฐ”๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. ๋ฐ”ํ…€ ๋‚ด๋น„๊ฒŒ์ด์…˜ ๋ฐ”์˜ ์•„์ดํ…œ์ด 3๊ฐœ์”ฉ์ด๋ฏ€๋กœ, ํ”„๋ž˜๊ทธ๋จผํŠธ๋„ 3๊ฐœ์”ฉ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. ํ”„๋ž˜๊ทธ๋จผํŠธ ๋‚ด๋ถ€์˜ ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ ์•กํ‹ฐ๋น„ํ‹ฐ ๊ฐ„ ์ด๋™๋„ ๊ฐ€๋Šฅํ•˜๋‹ค.
 

#3-2 ์‚ดํŽด๋ณด๊ธฐ์šฉ ์•ฑ์„ ๋งŒ๋“ค๊ธฐ ์œ„ํ•œ ํ…œํ”Œ๋ฆฟ

[File] โ†’ [New] โ†’ [New Project...] โ†’ [Bottom Navigation Views Activity]์˜ ํ…œํ”Œ๋ฆฟ์œผ๋กœ ํ”„๋กœ์ ํŠธ๋ฅผ ๋งŒ๋“ค๊ณ , ์ˆ˜์ •ํ–ˆ๋‹ค.
 

#3-3 MainActivity.kt

// package com.example.fragmentlifecyclelogger

import android.content.Intent
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.navigation.NavController
import androidx.navigation.findNavController
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.setupActionBarWithNavController
import com.example.fragmentlifecyclelogger.databinding.ActivityMainBinding
import com.google.android.material.bottomnavigation.BottomNavigationView

class MainActivity : AppCompatActivity(), OnBottomNavUiChangeListener {

    private lateinit var binding: ActivityMainBinding
    private lateinit var navView: BottomNavigationView
    private lateinit var navController: NavController

    override fun onCreate(savedInstanceState: Bundle?) {
        Log.i("interfacer_han", "MainActivity.onCreate()")
        super.onCreate(savedInstanceState)

        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        navView = binding.navView
        navView.setOnItemSelectedListener { item ->
            Log.i("interfacer_han", "(MainActivity) ${item.title} clicked")
            navController.navigate(item.itemId)
            true
        }

        navController = findNavController(R.id.nav_host_fragment_activity_main)
        // Passing each menu ID as a set of Ids because each
        // menu should be considered as top level destinations.
        val appBarConfiguration = AppBarConfiguration(
            setOf(
                R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications
            )
        )
        setupActionBarWithNavController(navController, appBarConfiguration)
        //navView.setupWithNavController(navController) // ์œ„์— ์žˆ๋Š” ์ปค์Šคํ…€ ๋ฆฌ์Šค๋„ˆ๋กœ ๋Œ€์ฒด

        navigateFragment()
    }

    override fun onStart() {
        Log.i("interfacer_han", "MainActivity.onStart()")
        super.onStart()
    }

    override fun onNewIntent(newIntent: Intent?) {
        super.onNewIntent(newIntent)
        intent = newIntent
    }

    private fun navigateFragment() {
        Log.i(
            "interfacer_han",
            "(MainActivity) intent.getStringExtra(\"fragment_info_key\"): ${intent.getStringExtra("fragment_info_key")}"
        )

        /* ์œ„์— ์žˆ๋Š” onNewIntent()๊ฐ€ ์žˆ์–ด์•ผ,
         * ์Šคํƒ์— ์žˆ๋‹ค๊ฐ€ ์žฌํ˜ธ์ถœ(onResume())๋œ Activity์˜ intent.getStringExtra("fragment_info_key")์˜ ๊ฐ’์ด
         * ํ•˜๋‚˜๋กœ ๊ณ ์ •๋˜์ง€ ์•Š๋Š”๋‹ค.
         */
        when (intent.getStringExtra("fragment_info_key")) {
            null -> {/* ์•„๋ฌด ๊ฒƒ๋„ ์•ˆํ•จ. ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์„ค์ •๋œ ํ”„๋ž˜๊ทธ๋จผํŠธ ํ˜ธ์ถœ๋จ */}

            "HomeFragment" -> {
                navController.navigate(R.id.navigation_home)
            }

            "DashboardFragment" -> {
                navController.navigate(R.id.navigation_dashboard)
            }

            "NotificationsFragment" -> {
                navController.navigate(R.id.navigation_notifications)
            }
        }
    }

    override fun onResume() {
        Log.i("interfacer_han", "MainActivity.onResume()")
        super.onResume()

        navigateFragment()
    }

    override fun onPause() {
        Log.i("interfacer_han", "MainActivity.onPause()")
        super.onPause()
    }

    override fun onStop() {
        Log.i("interfacer_han", "MainActivity.onStop()")
        super.onStop()
    }

    override fun onRestart() {
        Log.i("interfacer_han", "MainActivity.onRestart()")
        super.onRestart()
    }

    override fun onDestroy() {
        Log.i("interfacer_han", "MainActivity.onDestroy()")
        super.onDestroy()
    }

    override fun changeBottomNavUi(selectedItemId: Int) {
        val menuItem = navView.menu.findItem(selectedItemId)
        if(!menuItem.isChecked) {
            menuItem.isChecked = true
        }
    }
}

SecondActivity์˜ ์ฝ”๋“œ๋„ ๊ฑฐ์˜ ๊ฐ™๋‹ค. ์ „์ฒด ์†Œ์Šค์ฝ”๋“œ๋Š” #5์— ์žˆ๋‹ค.
 

#3-4 HomeFragment.kt

// package com.example.fragmentlifecyclelogger.ui.home

import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import androidx.fragment.app.Fragment
import com.example.fragmentlifecyclelogger.OnBottomNavUiChangeListener
import com.example.fragmentlifecyclelogger.R
import com.example.fragmentlifecyclelogger.SecondActivity
import com.example.fragmentlifecyclelogger.databinding.FragmentHomeBinding

class HomeFragment : Fragment() {

    private var _binding: FragmentHomeBinding? = null

    // This property is only valid between onCreateView and
    // onDestroyView.
    private val binding get() = _binding!!

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        Log.i("interfacer_han", "(MainActivity) HomeFragment.onCreateView()")
        _binding = FragmentHomeBinding.inflate(inflater, container, false)
        val root: View = binding.root

        val button: Button = binding.buttonHome
        button.setOnClickListener {
            val intent = Intent(activity, SecondActivity::class.java)
            intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) // ์ด ํ”Œ๋ž˜๊ทธ๊ฐ€ ์—†์œผ๋ฉด, Activity๋ฅผ ์ „ํ™˜ํ•  ๋•Œ๋งˆ๋‹ค Activity๊ฐ€ onCreate()๋จ
            intent.putExtra("fragment_info_key", "Home2Fragment")
            startActivity(intent)
        }
        return root
    }

    override fun onDestroyView() {
        Log.i("interfacer_han", "(MainActivity) HomeFragment.onDestoryView()")
        super.onDestroyView()
        _binding = null
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        Log.i("interfacer_han", "(MainActivity) HomeFragment.onCreate()")
        super.onCreate(savedInstanceState)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        Log.i("interfacer_han", "(MainActivity) HomeFragment.onViewCreated()")
        super.onViewCreated(view, savedInstanceState)
    }

    override fun onViewStateRestored(savedInstanceState: Bundle?) {
        Log.i("interfacer_han", "(MainActivity) HomeFragment.onViewStateRestored()")
        super.onViewStateRestored(savedInstanceState)
    }

    override fun onStart() {
        Log.i("interfacer_han", "(MainActivity) HomeFragment.onStart()")
        super.onStart()

        val nowActivity = activity
        if(nowActivity is OnBottomNavUiChangeListener) {
            nowActivity.changeBottomNavUi(R.id.navigation_home)
        }
    }

    override fun onResume() {
        Log.i("interfacer_han", "(MainActivity) HomeFragment.onResume()")
        super.onResume()
    }

    override fun onPause() {
        Log.i("interfacer_han", "(MainActivity) HomeFragment.onPause()")
        super.onPause()
    }

    override fun onStop() {
        Log.i("interfacer_han", "(MainActivity) HomeFragment.onStop()")
        super.onStop()
    }

    override fun onSaveInstanceState(outState: Bundle) {
        Log.i("interfacer_han", "(MainActivity) HomeFragment.onSaveInstanceState()")
        super.onSaveInstanceState(outState)
    }

    override fun onDestroy() {
        Log.i("interfacer_han", "(MainActivity) HomeFragment.onDestroy()")
        super.onDestroy()
    }
}

๋‚˜๋จธ์ง€ 5๊ฐœ์˜ ํ”„๋ž˜๊ทธ๋จผํŠธ๋“ค์˜ ์ฝ”๋“œ๋„ ๊ฑฐ์˜ ๊ฐ™๋‹ค. ์ „์ฒด ์†Œ์Šค์ฝ”๋“œ๋Š” #5์— ์žˆ๋‹ค.
 

#4 ๋กœ๊ทธ ํ™•์ธ

์•กํ‹ฐ๋น„ํ‹ฐ์˜ ์ƒ๋ช…์ฃผ๊ธฐ๋Š” ๋นจ๊ฐ„์ƒ‰ ๊ธ€์”จ๋กœ ํ‘œ์‹œํ–ˆ๋‹ค.
 

๋”๋ณด๊ธฐ

1. ์‹œ์ž‘ ํ™”๋ฉด (MainActivity)
    MainActivity.onCreate()
    HomeFragment.onCreate()
    HomeFragment.onCreateView()
    HomeFragment.onViewCreated()
    MainActivity.onStart()
    HomeFragment.onViewStateRestored()
    HomeFragment.onStart()
    MainActivity.onResume()
    HomeFragment.onResume()
    
2. MainActivity ๋‚ด์—์„œ Dashboard ํ”„๋ž˜๊ทธ๋จผํŠธ๋กœ ์ „ํ™˜
    HomeFragment.onPause()
    HomeFragment.onStop()
    DashboardFragment.onCreate()
    DashboardFragment.onCreateView()
    DashboardFragment.onViewCreated()
    DashboardFragment.onViewStateRestored()
    DashboardFragment.onStart()
    HomeFragment.onDestoryView()
    DashboardFragment.onResume()
    
3. SecondActivity์˜ Dashboard2 ํ”„๋ž˜๊ทธ๋จผํŠธ๋กœ ์ด๋™
    MainActivity.onPause()
    DashboardFragment.onPause()
    SecondActivity.onCreate()
    Home2Fragment.onCreate()
    Home2Fragment.onCreateView()
    Home2Fragment.onViewCreated()
    SecondActivity.onStart()
    Home2Fragment.onViewStateRestored()
    Dashboard2Fragment.onCreate()
    Dashboard2Fragment.onCreateView()
    Dashboard2Fragment.onViewCreated()
    Dashboard2Fragment.onViewStateRestored()
    Home2Fragment.onDestoryView()
    Dashboard2Fragment.onStart()
    SecondActivity.onResume()
    Dashboard2Fragment.onStop()
    Dashboard2Fragment.onCreate()
    Dashboard2Fragment.onCreateView()
    Dashboard2Fragment.onViewCreated()
    Dashboard2Fragment.onViewStateRestored()
    Dashboard2Fragment.onStart()
    Dashboard2Fragment.onDestoryView()
    Dashboard2Fragment.onResume()
    MainActivity.onStop()
    DashboardFragment.onStop()
    HomeFragment.onSaveInstanceState()
    DashboardFragment.onSaveInstanceState()
    
4. SecondActivity ๋‚ด์—์„œ Notification2 ํ”„๋ž˜๊ทธ๋จผํŠธ๋กœ ์ „ํ™˜
    Dashboard2Fragment.onPause()
    Dashboard2Fragment.onStop()
    Notifications2Fragment.onCreate()
    Notifications2Fragment.onCreateView()
    Notifications2Fragment.onViewCreated()
    Notifications2Fragment.onViewStateRestored()
    Notifications2Fragment.onStart()
    Dashboard2Fragment.onDestoryView()
    Notifications2Fragment.onResume()
    
5. MainActivity์˜ Notification ํ”„๋ž˜๊ทธ๋จผํŠธ๋กœ ์ด๋™
    SecondActivity.onPause()
    Notifications2Fragment.onPause()
    MainActivity.onRestart()
    MainActivity.onStart()
    DashboardFragment.onStart()
    MainActivity.onResume()
    DashboardFragment.onStop()
    NotificationsFragment.onCreate()
    NotificationsFragment.onCreateView()
    NotificationsFragment.onViewCreated()
    NotificationsFragment.onViewStateRestored()
    NotificationsFragment.onStart()
    DashboardFragment.onDestoryView()
    NotificationsFragment.onResume()
    SecondActivity.onStop()
    Notifications2Fragment.onStop()
    Dashboard2Fragment.onSaveInstanceState()
    Notifications2Fragment.onSaveInstanceState()
    Home2Fragment.onSaveInstanceState()
    Dashboard2Fragment.onSaveInstanceState()

6. MainActivity ๋‚ด์—์„œ Dashboard ํ”„๋ž˜๊ทธ๋จผํŠธ๋กœ ์ „ํ™˜
    NotificationsFragment.onPause()
    NotificationsFragment.onStop()
    DashboardFragment.onCreate()
    DashboardFragment.onCreateView()
    DashboardFragment.onViewCreated()
    DashboardFragment.onViewStateRestored()
    DashboardFragment.onStart()
    NotificationsFragment.onDestoryView()
    DashboardFragment.onResume()

 

#5 ์š”์•ฝ

ํ”„๋ž˜๊ทธ๋จผํŠธ๋Š” ์ž‘์€ Activity์ฒ˜๋Ÿผ ๋™์ž‘ํ•œ๋‹ค.
 

#6 ์™„์„ฑ๋œ ์•ฑ

https://github.com/Kanmanemone/android-practice/tree/master/lifecycle/FragmentLifecycleLogger