본문 바로가기

앱 개발/Chapter_Curriculum

[과제] Fragment 정리

< Fragment LifeCycle >

 

1) onAttach()
프래그먼트가 액티비티에 붙을 때 호출된다. 프래그먼트가 완벽하게 생성된 상태는 아니며 인자로 context가 주어진다. 

2) onCreate()
프래그먼트를 생성하면서 넘겨준 값들이 있다면 여기서 변수에 넣어주면 되지만 UI는 초기화 할 수 없다. 본격적으로 프래그먼트가 액티비티에 호출을 받아 생성되는 시점이다. 액티비티의 onCreate()에선 View 관련 작업을 할 수 있으나, 프래그먼트의 onCreate()에서는 할 수 없다.

3) onCreateView()
레이아웃을 인플레이트(inflate)하고, 버튼이나 텍스트뷰 등을 초기화할 수 있다. 프래그먼트가 자신의 인터페이스를 처음 그리기 위해 호출한다. 프래그먼트에 관련된 UI 바인딩 작업을 할 수 있다. onCreateView의 매개변수로 전달되는 container가 액티비티의 ViewGroup이며 프래그먼트가 위치하게 된다. 또 다른 매개변수인 savedInstanceState는 Bundle 객체로 프래그먼트가 재개되는 경우 이전 상태에 대한 데이터를 제공한다.
 
4) onActivityCreated()
프래그먼트에서 onCreateView를 마치고 액티비티에서 onCreate가 호출되고 나서 호출된다. 액티비티와 프래그먼트의 뷰가 모두 생성된 상태로서 View를 변경하는 작업이 가능한 단계이다. 액티비티와 프래그먼트가 연결된 상태이다.
 
5) onStart()
프래그먼트가 사용자에게 보이도록 해주는 단계이다. 액티비티처럼 프래그먼트가 화면에 보여지기 직전에 빠르게 실행된다.
 
6) onResume()
프래그먼트가 화면에 보여지기 시작하는 단계이며 사용자와의 상호작용이 가능하다. 액티비티와 마찬가지로 이벤트가 발생하여 프래그먼트가 가려지기 전까지 이 상태가 유지된다.
 
7) onPause()
프래그먼트는 사용자와의 상호작용을 중지한다. 다른 프래그먼트가 add되는 경우 일시정지 상태로 들어간다. UI 관련 처리를 정지하고 중요한 데이터를 저장한다.
 
8) onStop()
프래그먼트는 더이상 보여지지 않으며  프래그먼트 기능이 중지된다. 액티비티를 다시 띄우면 이전 상태가 그대로 보여진다.
 
9) onDestroyView()
프래그먼트와 관련된 View가 제거될 때 실행된다. 액티비티에서 프래그먼트 생성 시 addToBackStack()를 요청했을 경우 onDestroy()를 호출하지 않고 인스턴스가 저장되어 있다가 프래그먼트를 다시 부를 때 onCreateView()를 실행하여 다시 화면에 보여지게 한다.
 
10) onDestroy()
View가 제거된 후 프래그먼트가 완전히 소멸되기 전에 호출된다.
 
11) onDetach()
프래그먼트가 완전히 소멸되고 액티비티와의 연결도 끊어질 때 실행된다.

 

 

 

< Fragment 데이터 전달 방식 >

 

1) FragmentManager에 Bundle로 Data 전달

 

Fragment 또는 Activity에서 다른 Fragment로 데이터를 전달할 때 사용하는 것이 Bundle()이다. 새로운 Fragment를 생성할 때 arguments에 Bundle()을 넘겨주게 된다. arguments는 Bundle()을 파라미터로 받고 Bundle()은 put..() 메서드를 호출하여 데이터를 담아서 arguments에 넘긴다.

 

- 전송하려는 Fragment class


val bundle = Bundle()
bundle.putString("key", "value")
 
val passBundleBFragment = PassBundleBFragment()
passBundleBFragment.arguments = bundle parentFragmentManager.beginTransaction()
.replace(R.id.fragment_container_bundle, PassBundleFragment())
.commit()


- 받을 Fragment class


override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
var result = arguments?.getString("key")
     return inflater.inflate(R.layout.fragment_pass_b, container, false)
    }


2) Fragment Result API를 사용하여 Data 전달


전송하려는 Fragment에 result Listener를 설정하여 FragmentManager에서 setFragmentResultListener를 호출한다. 받으려는 Fragment에서는 result 를 생성한다. 그리고 setFragmentResult() API를 이용한다.

 

- 의존성 추가

// (AppModule)
dependencies {
    implementation "androidx.fragment:fragment-ktx:1.3.0"
}


- 전송하려는 Fragment class

button.setOnClickListener {
    val result = "result"
    setFragmentResult("requestKey", bundleOf("bundleKey" to result))
    parentFragmentManager.beginTransaction()
       .replace(R.id.fragment_container_bundle, PassBundleFragment())
       .commit()
}


- 받을 Fragment class

setFragmentResultListener("requestKey") { requestKey, bundle ->
    val result = bundle.getString("bundleKey")       
}
// "requestKey"는 사용하는 Fragment에서 어떤 listener에게 데이터를 전달할 지 결정하기 위한 식별자로 사용된다.
다른 fragment에서 같은 "requestKey"로 setFragmentResultListener를 적용할 때 마지막에 적용한 listener가 호출된다.


3) ViewModel을 이용한 Data 전달


하나의 Activity에서 container로 여러 Fragment를 이동하는 경우에 사용할 수 있다. Fragment가 Activity 하위에 위치하기 때문에 가능한 것이다. Activity를 공유하는 여러 Fragment들은 Activity의 메모리를 공유할 수 있고 AAC의 ViewModel은 Activity의 lifecycle보다 길기 때문에 공통의 Activity ViewModel을 사용하여 데이터 전달이 가능하다. 공통의 메모리 데이터를 이용하여 서로의 데이터를 전달하는 방법이다.

class ViewModelPassActivity : AppCompatActivity() {
    val viewModel : PassingViewModel by viewModels()
}

class PassAFragment : Fragment() {
    val viewModel : PassingViewModel by activityViewModels()
}

class PassBFragment : Fragment() {
    val viewModel: PassingViewModel by activityViewModels()
}


// Activity에 Fragment들이 같은 데이터를 바라볼 수 있도록 ViewModel 객체를 만들고 그 객체에 데이터를 전달하여 간결하게 Fragment 통신을 달성할 수 있다.



4) Jetpack Navigation에서 제공하는 safe-args로 전달

 

navigation.xml에서 화면전환에 필요한 액션과 data 및 defaultValue를 정의 가능하다. 전달하는 데이터 타입이 받는 곳의 데이터 타입과 다를 경우에 compile 에러를 일으켜 의도하지 않은 상황이 발생할 확률을 줄였다. 간결하고 안정적인 처리를 할 수 있지만 다른 전달 방식보다 환경 세팅할 것과 알아야 할 기능들이 많다.


//Navigation.xml에서 이동할 화면에 대한 정의(action)와 전달할 데이터(argument)를 정의한다.
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/nav_graph"
    app:startDestination="@id/passArgsAFragment">

    <fragment
        android:id="@+id/passArgsAFragment"
        android:name="cohttp://m.gunt.fragmentdatapassexample.pass.passargs.PassArgsAFragment"
        android:label="PassArgsAFragment" >
        <action
            android:id="@+id/passAToB"
            app:destination="@id/passArgsBFragment"
            app:launchSingleTop="true" />
        <argument
            android:name="argsString"
            app:argType="string"
            android:defaultValue=""/>
    </fragment>
    <fragment
        android:id="@+id/passArgsBFragment"
        android:name="cohttp://m.gunt.fragmentdatapassexample.pass.passargs.PassArgsBFragment"
        android:label="PassArgsBFragment" >
        <action
            android:id="@+id/passBToA"
            app:destination="@id/passArgsAFragment"
            app:launchSingleTop="true"
            app:popUpTo="@id/nav_graph" />
        <argument
            android:name="argsString"
            app:argType="string"
            android:defaultValue=""/>
    </fragment>
</navigation>

 

- 전송하려는 Fragment class

//액션에 본인이 보내려는 데이터를 담아 액션을 수행한다.
binding.btnSend.setOnClickListener {
    val action = PassArgsAFragmentDirections.passAToB(binding.etText.text.toString())
    findNavController().navigate(action)
}


- 받을 Fragment class

 

val args: PassArgsAFragmentArgs by navArgs()
binding.textView.text = args.argsString

728x90

'앱 개발 > Chapter_Curriculum' 카테고리의 다른 글

[과제] 피드백 (Android 입문)  (0) 2024.03.29
[과제] Activity 정리  (0) 2024.03.28
[과제] UI xml 연습 후기  (0) 2024.03.26
[과제] Android 입문  (0) 2024.03.22
Chapter3-1 (앱 개발 입문)  (0) 2024.03.20