개발/Android

Fragment 프래그먼트

Debin 2022. 5. 31.
반응형

Fragment (프래그먼트)

  • 프래그먼트 는 일종의 컴포넌트 같은 개념이다.
  • 여러 개의 프래그먼트를 하나의 액티비티에 결합하여 창이 여러 개인 UI를 빌드할 수 있다.
  • 그리고 하나의 프래그먼트를 여러 액티비티에서 재사용할 수 있습니다.
  • 프래그먼트는 액티비티처럼 레이아웃을 가진 독립적인 개체로서, 자체적인 생명주기를 가지고 액티비티 실행 중에 화면에 동적으로 추가되거나 다른 프래그먼트로 교체가 가능하다.
  • 한 개의 액티비티에 들어가는 화면 요소를 프래그먼트 단위로 나누어 관리하기 때문에 레이아웃을 분리 관리할 수 있고, 액티비티의 화면 구성을 위한 레이아웃의 복잡도도 줄일 수 있다.
  • 프래그먼트는 항상 액티비티 내에서 호스팅되어야 하며, 해당 프래그먼트의 생명주기는 호스트 액티비티의 생명주기에 직접적으로 영향을 받는다.
  • 예를 들어 액티비티가 일시정지되는 경우, 그 안의 모든 프래그먼트도 일시정지된다. 마찬가지로 액티비티가 소멸하면 그 안의 모든 프래그먼트도 소멸한다.

스마트폰 화면 구성

 

How Fragments Work (프래그먼트 동작 방식)

  • 프래그먼트는 FragmentManager에 의해 관리되며, 프래그먼트 트랜잭션(추가, 교체, 삭제 등) 수행은 FragmentManager로부터 FragmentTransaction 인스턴스를 가져와 사용한다. 
  • supportFragmentManager.beginTransaction()

프래그먼트 동작 방식

Fragment lifecycle (프래그먼트 생명주기)

  • onAttach(): 프래그먼트가 액티비티와 연결될 때 호출 (이 시점부터 프래그먼트가 동작한다.)
  • onCreate(): 프래그먼트가 초기화될 때 호출된다.
  • onCreateView(): 시스템은 프래그먼트가 자신의 사용자 인터페이스를 처음으로 구성할 때 이 메서드를 호출한다.
    프래그먼트에 맞는 UI를 그리려면 메서드에서 View
    를 반환해야 하며, 이 메서드는 프래그먼트 레이아웃의 root다.
    프래그먼트가 UI를 제공하지 않는 경우 null을 반환한다.
  • onActivityCreated(): 액티비티의 onCreate() 메서드가 반환할 때 호출된다.
  • onStart(): 프래그먼트가 보여질 수 있을 때 호출된다.
  • onResume(): 프래그먼트가 사용자와 상호작용할 수 있을 때 호출된다.
  • onPause(): 시스템이 이 메서드를 호출하는 것은 유저가 프래그먼트 사용을 중지한다는 것을 암시한다.
  • onStop(): 프래그먼트나 부모 액티비티가 중지 됐을 때 호출 View의 상태 값을 저장하는 함수다.
  • onDestroyView(): 프로그먼트 View에 대한 모든 참조를 해제할 수 있도록 호출한다.
  • onDestroy(): 프래그먼트가 완전히 제거되거나 FragmentManager가 destroy 되었을 때 호출된다.
  • onDetach(): onDestory()가 호출된 후 호출된다.

Fragment lifecycle

프래그먼트 주요 클래스

클래스 요약
Fragment.SavedState FragmentManager.saveFragmentInstanceState() 메소드에 의해 저장된 프래그먼트 상태 정보
FragmentManager 액티비티 내에서 프래그먼트 객체와 상호작용하기 위한 인터페이스를 제공하는 프래그먼트 매니저
FragmentTransaction 프래그먼트를 추가하거나 제거 또는 삭제 등을 수행할 수 있는 프래그먼트 트랜잭션

Activity 내의 Fragment를 관리하기 위해서는 FragmentManager를 사용한다.

FragmentManager가 할 수 있는 일은 아래와 같은 일이 있다.

  • findFragmentById() or findFragmentByTag()로 Fragment 가져오기
  • popBackStack()을 사용하여 Fragment를 BackStack에서 꺼내기
  • beginTransaction()을 사용하여 FragmentTransaction을 가져오기

FragmentTransaction을 이용하여 아래와 같은 일을 할 수 있다.

  • add(): Fragment 추가
  • remove(): Fragment 제거
  • replace(): Fragment 변경

프레그먼트 사용 예시 코드

먼저 first_fragment_exam.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=".FirstFragmentExamMainActivity">

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/fragmentContainerView"
        android:layout_width="match_parent"
        android:layout_height="600dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/btn_fragment_1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:text="프래그먼트 1"
        app:layout_constraintEnd_toStartOf="@+id/btn_fragment_2"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/fragmentContainerView" />

    <Button
        android:id="@+id/btn_fragment_2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="프래그먼트 2"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/btn_fragment_1"
        app:layout_constraintTop_toTopOf="@+id/btn_fragment_1" />
</androidx.constraintlayout.widget.ConstraintLayout>

다음은 first_fragment_exam_first_fragment.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:layout_height="match_parent"
    android:background="@color/fragment_first">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Fragment 1"
        android:textColor="@color/black"
        android:textSize="30sp"
        android:layout_marginTop="300dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/btn_go_second"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:text="Go to Fragment-2"
        android:textAllCaps="false"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView" />
</androidx.constraintlayout.widget.ConstraintLayout>

다음은 first_fragment_exam_second_fragment.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:layout_height="match_parent"
    android:background="@color/fragment_second">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Fragment 2"
        android:textColor="@color/black"
        android:textSize="30sp"
        android:layout_marginTop="300dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/btn_go_first"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:text="Go to Fragment-1"
        android:textAllCaps="false"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView" />
</androidx.constraintlayout.widget.ConstraintLayout>

이제 프래그먼트를 구현한 코틀린 코드와 액티비티 코드다.

먼저 사용되는 프래그먼트 2개에 관한 코드다.

class FragmentFirst : Fragment() {
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {


        val view = inflater.inflate(R.layout.first_fragment_exam_first_fragment, container, false)
        view.findViewById<Button>(R.id.btn_go_second).setOnClickListener{
            (activity as FirstFragmentExamMainActivity).onReplaceFragment(FragmentSecond());
        }
        return view;
    }
}

class FragmentSecond : Fragment() {
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {

        val view = inflater.inflate(R.layout.first_fragment_exam_second_fragment, container, false)

        view.findViewById<Button>(R.id.btn_go_first).setOnClickListener{
            (activity as FirstFragmentExamMainActivity).onReplaceFragment(FragmentFirst());
        }
        return view
    }
}

 마지막으로 FirstFragmentExamMainActivity 클래스 코드다.

class FirstFragmentExamMainActivity : AppCompatActivity() {

    val binding by lazy{
        FirstFragmentExamBinding.inflate(layoutInflater)
    }

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

        binding.btnFragment1.setOnClickListener{
            onReplaceFragment(FragmentFirst())
        }

        binding.btnFragment2.setOnClickListener{
            onReplaceFragment(FragmentSecond())
        }
    }

    fun onReplaceFragment(fragment: Fragment){
        val ft = supportFragmentManager.beginTransaction()
        ft.replace(R.id.fragmentContainerView,fragment).commit()
    }

}

그럼 메인 화면에서 버튼을 누르면 아래와 같은 두 UI를 확인할 수 있다.

 

이상으로 포스팅을 마칩니다. 감사합니다!

 

참고자료

https://developer.android.com/guide/components/fragments?hl=ko

반응형

댓글