[Kotlin 개념] 프래그먼트 (Fragment)

이다을·2023년 9월 13일
0

프래그먼트 (Fragment)

하나의 액티비티 안에 여러 화면을 만들어 넣을 수 있는 View 공간

1. Fragment란?

  • 액티비티 위에서 동작하는 모듈화된 사용자 인터페이스 입니다.
  • Fragment는 재사용 가능하며 여러 Activity와 함께 존재할 수 있습니다.
  • 큰 화면 크기에 대한 더 유연하고 적응적인 UI 디자인을 허용합니다.
  • 하나의 액티비티 위에서 프래그먼트를 활용해 여러개의 UI를 생성할 수 있습니다.
  • 하나의 프래그먼트를 여러개의 액티비티에서 재사용할 수 있습니다.
  • ⚠️ 액티비티와 분리되어 독립적으로 동작할 수는 없습니다.

2. Fragment를 사용하는 이유

  • 액티비티로 화면을 계속 넘기는 것 보다는 프래그먼트로 같은 액티비티 안에서 일부만 바꾸어주면 자원 이용량이 적어 속도가 빠르고 가볍기 때문입니다.
  • 모듈성: 복잡한 UI를 더 작고 재사용 가능한 부분으로 분리해서 관리가 가능합니다.
  • 적응성: 별도의 활동을 만들지 않고도 다양한 화면 크기에 맞게 UI를 조정합니다.
  • 재사용성: 여러 활동에서 동일한 fragment를 사용합니다.

3. Fragment와 Activity의 차이점

  • 액티비티(Activity)
    • 시스템의 액티비티 매니저에서 인텐드를 해석해 액티비티간의 데이터를 전달 합니다.
  • 프래그먼트(Fragment)
    • 액티비티의 프래그먼트 매니저에서 메소드로 프래그먼트간 데이터를 전달 합니다.

4. Fragment 생명 주기

  • OnAttach()
    • Activity에 Fragment가 붙을 때 호출된다.
    • Fragment가 완벽하게 생성된 상태는 아니다.
    • 인자로 context가 주어진다.

  • onCreate()
    • Activity와 같이 초기화가 필요한 리소스들을 초기화한다.
    • Fragment를 생성하면서 넘겨준 값이 있다면, 여기서 변수에 넣어준다.
    • UI 초기화는 하지 못한다.

  • onCreateView()
    • xml에 표기된 Layout들을 객체화해서 사용할 수 있게 해주는 곳이다.
    • Layout객체를 얻을 수 있으므로, 버튼이나 텍스트뷰 등을 초기화 할 수 있다.
    • View를 반환해야 한다. (UI를 제공하지 않는 경우에는 Null을 반환)
    • Fragment에 속한 View나 ViewGroup에 대한 UI 바인딩 작업을 할 수 있다.
    • Fragment에서 UI를 그릴 때 호출되는 콜백이다.
    • 매개변수 container는 Activity의 ViewGroup이며, 여기에 Fragment가 위치하게 된다.
    • 매개변수 savedInstanceState는 Bundle 객체로 Fragment가 재개되는 경우 이전 상태에 대한 데이터를 제공한다.

  • onViewCreated()
    • onCreateView()를 통해 반환 된 View 객체는 onViewCreated()의 파라미터로 전달 된다.
    • 이 때 Lifecycle이 INITIALIZED 상태로 업데이트가 된다.
    • 때문에 View의 초기 값 설정, LiveData 옵저빙, RecyclerView, ViewPager2에 사용될 Adapter 세팅은 이 메소드에서 해주는 것이 적절하다.

  • onActivityCreated()
    • Fragment에서 onCreateView를 마치고, Activity에서 onCreate()가 호출되고 나서 호출된다.
    • Activity와 Fragment의 뷰가 모두 생성된 상태로, View를 변경하는 작업이 가능한 단계이다.
    • Activity에서 Fragment를 모두 생성하고 난 다음에 호출된다.
    • Acitvity와 Fragment의 View가 모두 생성되고, 연결된 상태이다.

  • onStart()
    • Fragment가 사용자에게 보여지기 직전 호출된다.

  • onResume()
    • Fragment가 화면에 보여지는 단계이다.
    • 사용자와의 상호 작용이 가능하다. ex) 버튼클릭
    • onPause() 되기 전까지는 이 단계에서 유지된다.

  • onPause()
    • Parent Activity가 아닌 다른 Activity가 위로 올라오거나, 다른 Fragment가 add되면서 포커스를 잃을 때 일시정지 상태로 들어간다.
    • Fragment와 사용자의 상호작용이 중지된다.
    • UI관련 처리를 정지하고, 중요한 데이터를 저장한다.

  • onStop()
    • Fragment가 완전히 가려지는 경우, onPause()에 이어 onStop() 까지 실행된다.
    • Fragment는 더이상 보이지 않고, Fragment 기능은 중지된다.
    • 이 단계에서 시스템이 자동으로 onStateInstance()를 호출하여 UI의 상태를 저장하므로Activity를 다시 띄우면 이전 상태 그대로 보인다.

  • onDestroyView()
    • Fragment와 관련된 View가 제거될 때 실행된다.
    • Activity에서 Fragment 생성 시 addToBackStack()을 요청했을 경우 onDestroy()를 호출하지 않고, 인스턴스가 저장되어 있다가 Fragment를 다시 부를 때 onCreateView()를 실행하여 다시 화면에 보여지게 한다.

  • onDestroy()
    • View가 제거된 후 Fragment가 완전히 소멸되기 전에 호출된다.

  • OnDetach()
    • Fragment가 완전히 소멸되고, Activity와의 연결도 끊어질 때 실행된다.

5. Fragment 사용 단계

build.gradle

dependencies {
    implementation("androidx.fragment:fragment-ktx:1.4.1")
}
  1. 프래그먼트 정의하기
    • 액티비티를 만들 때와 비슷하게, 하나의 Kotlin 소스 파일과 하나의 XML 레이아웃로 정의
  2. 프래그먼트를 액티비티의 레이아웃 파일에 정적 추가하기
    • 프래그먼트를 액티비티의 레이아웃 파일 안에서 선언
  3. Kotlin 코드에서 동적으로 프래그먼트 추가하기

6. Fragment 실행 순서

  • 👉 1) 프로젝트를 생성한다.
  • 👉 2) 안드로이드스튜디오에서 File → New → Fragment → Fragment(Blank)
    • 원하는 개수만큼 Fragment를 만든다.
  • 👉 3) ConfigureComponent대화 창에서 아래와 같이 설정 후, Finish 버튼을 클릭
    • FragmentName값을 FirstFragement로 설정
    • FragmentLayoutName값을 fragment_first로 설정
    • SourceLanguage : Kotlin
  • 👉 4) [확인]프로젝트에서 다음의 변경사항을 확인해본다.
    • FirstFragment클래스가 생성됨
    • fragment_first.xml파일이 생성됨
  • 👉 5) 자동으로 생성 된 fragment_first.xml파일
    // 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="프래그먼트 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>
  • 👉 6) 자동으로 생성 된 fragment_second.xml파일
    // 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>
  • 👉 7) activity_main.xml 파일을 열고, fragment를 표시할 FrameLayout과 버튼 2개 추가
    // activity_main.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"
        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>
  • 👉 8) 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 { // 1번
                fragment1Btn.setOnClickListener{
                    setFragment(FirstFragment()) // 2번
                }
                fragment2Btn.setOnClickListener {
                    setFragment(SecondFragment())
                }
            }
            setFragment(FirstFragment()) // 첫 화면에서 보여질 기본 View
        }
    
        private fun setFragment(frag : Fragment) { // 3번
            supportFragmentManager.commit {
                replace(R.id.frameLayout, frag)
                setReorderingAllowed(true)
                addToBackStack("")
            }
        }
    }
  • 1번 : activity_main.xml 에 만든 버튼 클릭 이벤트
  • 2번 : 버튼을 누르면 함수를 호출, FirstFragment와 SecondFragment를 넘겨줌
    • supportFragmentManager : 사용자 상호작용에 응답해 Fragment를 추가하거나 삭제하는 등 작업을 할 수 있게 해주는 매니저
    • replace : 어느 프레임 레이아웃에 띄울 것이냐, 어떤 프래그먼트냐
    • setReorderingAllowed : 애니메이션과 전환이 올바르게 작동하도록 트랜잭션과 관련된 프래그먼트의 상태 변경을 최적화
    • addToBackStack : 뒤로가기 버튼 클릭 시 다음 액션 (이전 fragment로 가거나 앱이 종료되거나)
  • 3번 : 파라미터로 사용할 Fragment를 받아와서 activity_main.xml에 만든 FrameLayout에 띄우는 함수
profile
나도 개발 할래

2개의 댓글

comment-user-thumbnail
2023년 9월 14일

복습하고 갑니다!

답글 달기
comment-user-thumbnail
2023년 9월 14일

공식 문서 안봐도 될 거 같아요! 자주 보러 올게요!

답글 달기