Unit 3-2

jiwon·2022년 1월 23일
0

코틀린

목록 보기
9/16
post-thumbnail
post-custom-banner

Fragments

지금까지 예제에서는 앱에 인텐트를 추가하여 액티비티 사이를 이동했다. 하지만 모든 화면마다 별도의 액티비티가 필요한 건 아니다. 여러 일반적인 UI 패턴(예: 탭)이 Fragment라는 섹션을 사용해 단일 액티비티 내에 존재한다.

하단 탭을 눌러 메뉴를 이동하면 인텐트가 트리거되지 않고(=다른 액티비티가 실행되지 않고) 이전 프래그먼트가 다른 프래그먼트로 교체된다.


위와 같이 단일 액티비티에 여러 프래그먼트가 동시에 존재 할 수도 있다.

프래그먼트 수명 주기

프래그먼트 수명 주기에는 Lifecycle.State 열거형으로 표현되는 다섯 가지 상태가 있다.

  • INITIALIZED: 프래그먼트의 새 인스턴스가 인스턴스화된다.
  • CREATED: 첫 번째 프래그먼트 수명 주기 메서드가 호출된다. 이 상태에서 프래그먼트와 연결된 뷰도 만들어진다.
  • STARTED: 프래그먼트가 화면에 표시되지만 '포커스'가 없으므로 사용자 입력에 응답할 수 없다.
  • RESUMED: 프래그먼트가 표시되고 포커스도 있다.
  • DESTROYED: 프래그먼트 객체의 인스턴스화가 취소된다.

액티비티와 마찬가지로 상태전환을 할 수 있는 여러 함수가 있다.
중간 부분을 뭉뚱그리고 생성/삭제 부분만 보면 프래그먼트 만들기- 뷰만들기/ 뷰 삭제-프래그먼트 삭제.. 이런 느낌?

※액티비티의 수명 주기와의 차이점
onCreate() 메서드에 차이가 있다.
액티비티에서는 onCreate()를 사용하여 레이아웃을 확장하고 뷰를 바인딩한다.
하지만 프레그먼트 수명 주기에서 onCreate()는 뷰가 만들어지기 전에 호출되므로 여기서 레이아웃을 확장할 수 없다.(대신 대신 onCreateView()에서 확장하고, onViewCreated()에서 특정 뷰에 바인딩할 수 있다.)

Jetpack Navigation Component

안드로이드 Jetpack 라이브러리는 Navigation component를 제공한다.

  • Navigation Graph: 대상(화면=여기선 프래그먼트)과 액티비티를 모두 포함하는 리소스 파일이다. 그래프는 앱의 모든 탐색 경로를 나타낸다.
  • NavHost: 액티비티 내에서 Navigation Graph의 대상을 표시하는데 사용된다. 프래그먼트 간 이동이 이루어지면 NavHost에 표시되는 대상이 업데이트된다.
  • NavController: NavController 객체를 사용하면 NavHost에 표시되는 Navigation들을 제어할 수 있다. 표시되는 프래그먼트를 교체하거나 이전 프래그먼트로 이동하는등..

NavHost 역할을 할 FragmentContainerView를 activity_main.xml에 작성해 보자! 이렇게 하면 앱의 모든 Navigation은 FragmentContainerView 내에서 실행되게 된다.

<FrameLayout  
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">


    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        app:defaultNavHost="true"
        app:navGraph="@navigation/nav_graph"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</FrameLayout>

app:navGraph="@navigation/nav_graph"에 생긴 오류에 대한 제안 사항을 눌러 nav_graph.xml을 만들자.

XML 파일을 만들면 새 편집기가 표시된다.
상단의 초록색+가 붙은 버튼을 눌러 프래그먼트들을 추가하고, 화살표로 연결해준다.


letterListFragment에서 선택한 단어가 wordListFragment로 전달되어야 한다. 단어가 매개변수로 전달될 수 있도록 arguments에서 +를 눌러 추가해준다.

그리고 집모양 버튼을 눌러 letterListFragment를 시작 화면으로 설정해 준다.

holder.button.setOnClickListener {
            val action = LetterListFragmentDirections.actionLetterListFragmentToWordListFragment(letter = holder.button.text.toString())
            holder.view.findNavController().navigate(action)

        }

LetterAdapter의 리스너도 적절히 작성해 준다.

private lateinit var navController: NavController
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        
        val navHostFragment = supportFragmentManager
            .findFragmentById(R.id.nav_host_fragment) as NavHostFragment
        navController = navHostFragment.navController

        setupActionBarWithNavController(navController)

    }
    override fun onSupportNavigateUp(): Boolean {
        return navController.navigateUp() || super.onSupportNavigateUp()
    }

MainActivity에서 navController를 설정하는 코드를 추가한다.

private lateinit var letterId: String
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        //let()은? arguments가 null이면 안쪽의 코드가 실행되지 않고 null이 아니면 실행됨.
        arguments?.let { 
            //it:bundle
            letterId = it.getString(LETTER).toString()
        }
    }

마지막으로 WordListFragment에서 매개변수를 받아오는 코드를 onCreate에 작성한다.

profile
개발 공부합니다. 파이팅!
post-custom-banner

0개의 댓글