Android-Kotlin/Android

[Android] Fragment 개념 및 간단 사용방법 Kotlin

주톨 2022. 6. 19. 18:44
728x90

 

Fragment는 무엇인가?

 

우리가 자주쓰는 카카오톡을 예로 들자 

카카오톡 검정색 테두리 부분이 Activity 부분이다. 

Activity안에 여러 Fragment를 만들어 넣을 수 있는 View공간을 만든다.  (하얀공간)

 

오른쪽 사진에 있는 버튼들을 누르면 만들어둔 Fragment들을 View공간(하얀공간)에 넣어서 우리에게 보여주는 것이다.

 

 

 

Fragment를 왜 사용할까?

 

내가 가장 먼저든 의문은 Activity로 화면을 계속 넘기면 되는 거 아닌가?
왜 Fragment를 사용해야 할까? 라는 것이었다.

 

└ 이거에대한 답변 :
      Activity로 화면을 계속 넘기는 것보다는 Fragment로 일부만 바꾸는 것이 자원 이용량이 적어
      속도가 빠르기 때문에....

 

Fragment를 사용하면  Activity를 적게 만들 수 있다. = Activity의 복잡도를 줄일 수 있다.

Fragment를 사용하면  재사용할 수 있는 레이아웃을 분리해서 관리가 가능하다.

 

Fragment를 사용하면 최소 1개의 Activity안에서 Fragment공간에 View만 집어넣으면 여러 Activity를 만들지 않아도

우리에게 여러 화면을 보여줄 수 있다.

 

 

 

Fragment 특징

 

1. Fragment 자체로 우리에게 보일 수 없다.

만들어둔 Fragment 화면이 우리에게 보이기 위해서는 Activity 안에 존재해야 한다.

2.  Fragment 만의 LifeCycle 이 존재한다.

3.  재사용이 가능하다.

 

 

 

 

Fragment LifeCycle(생명주기)

 

 

출처 : https://stackoverflow.com/questions/51614834/what-is-lifecycle-of-dialogfragment

 

 

1. On Attach()

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

2. On Create()

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

3.  On CreateView()

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

4. On ActivityCreated() 

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

5. On Start()

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

6. On Resume()

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

7. On Pause()

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

8. On Stop()

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

9. On DestoryView()

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

10. On Destroy()

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

11. On Detach()

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

 

 

Fragment 사용방법

 

시작하기전에 Fragment KTX 를 사용하기 위해 build.gradle 에 다음과 같이 추가한다.

dependencies {
    implementation("androidx.fragment:fragment-ktx:1.4.1")
}

 

위와 같이 작동하는 프로젝트를 만들어보자!

 

새로운 Activity만드는 방식과 비슷하다.

Fragment(Blank)를 누르고 이름을 지정한 다음 Finish를 누르면 된다.

Fragment를 총 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"
        app:layout_goneMarginTop="10dp">

    </FrameLayout>

    <Button
        android:id="@+id/fragment1_btn"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:text="Go 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="Go 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>

여기서 볼 것은 Fragment를 사용하려면 FramLayout을 만들고 그 안에 넣어야 한다!
FrameLayout은 여러 화면을 쌓듯이(프레임 쌓듯이) 화면 위에 또 다른 화면을 가져와 띄울 수 있다.

 

 

*fragment_1.xml

간단하게 텍스트 뷰만 띄우기로 해요.

 

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    tools:context=".Fragment1">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="This Frag1"
        android:textAllCaps="false"
        android:textSize="48sp"
        android:background="@color/white"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"/>


</androidx.constraintlayout.widget.ConstraintLayout>

 

 

*fragment_2.xml

    fragment_1.xml 과 똑같이 만들어주고 Text만 "This Frag2" 로 수정하시면 됩니다.

 

 

 

 

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.run {  // 1번
            fragment1Btn.setOnClickListener{
                setFragment(Fragment1()) //3번
            }
            fragment2Btn.setOnClickListener {
                setFragment(Fragment2())
            }
        }
    }

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

 

코드분석

ViewBinding을 사용했습니다. (모르시면,,,검색!! 쉽습니다)

 

1번코드 :  activity_main.xml 에 만든 버튼2가지 클릭이벤트 처리!

 

2번코드 :  함수를 하나 만들었습니다. 이 함수가 하는 역할은 파라미터로 사용할 Fragment를 받아와서 
                  activity_main.xml에 만든 FrameLayout에 띄우는 간단한 함수입니다.

 

supportFragmentManager.commit  {}  :  사용자 상호작용에 응답해 Fragment를 추가하거나 삭제하는등 작업을
할 수 있게 해주는 매니저 라고 생각하시면 편합니다.

replace(R.id.frameLayout, frag) :  replace(어느프레임 레이아웃에 띄울것이냐, 어떤프래그먼트냐)
어느프레임레이아웃에 띄울것이냐 : 아까 우리가만든 FrameLayout에 ID값 넣어줬죠? 그거 넣으시면됩니다.

어떤프래그먼트냐 : 우리가 함수를 만들때 프래그먼트를 인자로 받아왔죠?  그거 넣으시면됩니다.

 

setReorderingAllowed(true) : 애니메이션과 전환이 올바르게 작동하도록 트랜잭션과 관련된 프래그먼트의 상태 변경을 최적화 하는거 입니다.  (사실 저도 잘 모릅니다.. 그냥 공식문서에서 쓰라고 했습니다!)

addToBackStack("")  : 이 코드를 넣으면뒤로 가기버튼을 눌렀을 시에 차이가 있는데요.
이 코드를 추가하면 뒤로가기 버튼을 누를시 FrameLayout에 겹쳐져있던 그 전의 Fragment를 보여줍니다.
이 코드를 추가하지않으면 뒤로가기 버튼을 누를시 바로 앱이 종료됩니다.  (한번추가하고 안하고 해서 실험해보세요!)

 

3번코드 : 이 코드는 버튼을 누르면 함수를 호출하는 간단한 코드입니다.
주의 깊게 볼 것은 함수를 호출할 때 무슨 값을 넘겨 줬는지입니다.

Fragment1() 과 Fragment2() 를 넘겨줬죠. 

 

이겁니다.  잘보시면 Fragment1은 클래스 형식으로 만들어져있습니다.  Fragment를 상속받았구요.

결국 우리가 함수를 호출할때 넘겨준것은 Fragment1 클래스를 객체화 해서 Fragment를 넘겨준것입니다.

Fragment1 클래스는 우리가 아까 만든  *fragment_1.xml 그겁니다. 

 setFragment(Fragment1()) = setFragment(어떤프래그먼트를 넘길거냐! 나는 Fragment1클래스를 객체화해서 만든 프래그먼트를 넘길것이다. !)

 

 

실행해 보시면 잘 될 것입니다..

제 부족한 설명력으로.. 이해시켜 드렸을지는 모르겠지만 글 읽어주셔서 감사합니다.
이해 안 가는 부분이 있으시거나 틀린 부분이 있으면 댓글 부탁드립니다.

 

 

 

 

참고사이트:
https://stackoverflow.com/questions/51614834/what-is-lifecycle-of-dialogfragment

https://asong-study-record.tistory.com/69

 

[안드로이드] 프래그먼트 생명주기(Fragment LifeCycle)

1. onAttach() 프래그먼트가 액티비티에 붙을 때 호출된다. 아직 프래그먼트가 완벽하게 생성된 상태는 아니며, 인자로 context가 주어진다. 2. onCreate() 액티비티와 마찬가지로 초기화해야하는 리소스

asong-study-record.tistory.com

https://readystory.tistory.com/199

 

[Android] 의외로 잘 모르는 Fragment 의 Lifecycle

많은 앱들이 여러가지 이유로 single activity application 을 지향하고 있습니다. 따라서 Fragment 로 UI 를 구성하는 경우가 굉장히 많은데요. 이때 많은 개발자들이 Activity 의 Lifecycle 에 대해서는 잘 알고

readystory.tistory.com