-
Fragment 3가지 데이터 전달 방식Android 2024. 4. 19. 21:01
1. Activity → Fragment
// MainActivity.kt fragment1Btn.setOnClickListener { // Activity -> Fragment 데이터 전달 val dataToSend = "Hello First Fragment! From Activity" val fragment = FirstFragment.newInstance(dataToSend) setFragment(fragment) }
Activity에서 Fragment에 데이터를 보내기 위해서는 먼저 데이터를 정의해야 한다.
이후 해당 프래그먼트의 싱글톤으로 정의된 newInstance함수의 매개변수로 해당 데이터를 넣어준다.
setFragment 함수는 저번 프래그먼트 포스팅에서 설명했는데, activity의 xml 내 framelayout으로 설정한 부분을 프래그먼트 화면으로 전환해주는 기능을 한다.
// FirstFragment.kt companion object { @JvmStatic fun newInstance(param1: String) = FirstFragment().apply { arguments = Bundle().apply { putString(ARG_PARAM1, param1) } } }
그럼 해당 프래그먼트의 함수에 param1으로 액티비티가 전달한 데이터가 담겨진다.
arguments 내에서는 bundle 형태로 param1 데이터가 key값과 함께 담기게 된다.
// FirstFragment.kt override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) arguments?.let { param1 = it.getString(ARG_PARAM1) } }
이후 onCreate 함수가 실행될때 데이터가 담긴 arguments에서 getString 함수와 key값을 통해 받아온 데이터를 꺼낼 수 있다. 해당 데이터는 param1에 저장된다.
// FirstFragment.kt private var param1: String? = null
기존에 null 값이었던 param1 은 onCreate 함수가 실행되고 데이터가 담겨있다는 조건하에 새로운 값으로 바뀐다.
// FirstFragment.kt override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // Activity -> Fragment binding.tv.text = param1 }
이후 프래그먼트에서 onViewCreated 함수가 실행될때 (이걸 보면서 fragment 생명 주기도 같이 공부해야 하는 이유가 자연스럽게 생길 것이다.) 받아온 param1 데이터 값을 원하는 뷰에 설정할 수 있다.
이렇게 하면 액티비티에서 프래그먼트로 데이터를 전달하는 과정은 끝났다!
2. Fragment → Fragment (1번이 이해가 되면 쉽게 이해할 수 있다!)
두번째 경우에서는 받는 fragment의 코드는 첫번째 경우와 동일하다. 대신, 보내는 프래그먼트의 코드를 유심히 볼 필요가 있다.
// FirstFragment.kt override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // fragment -> fragment binding.button.setOnClickListener { val dataToSend = "Hello Fragment2 from Fragment1" val fragment2 = SecondFragment.newInstance(dataToSend) // 핵심 코드 requireActivity().supportFragmentManager.beginTransaction() .replace(R.id.frameLayout,fragment2) .addToBackStack(null) .commit() } }
fragment 에서 데이터를 보낼 때는 onViewCreated 함수에다 작성해야 한다 (이유는 프래그먼트 생명 주기를 이해하게 되면 내용을 더 추가해볼 예정이다!)
보내줄 데이터(dataToSend)를 생성하고 그 데이터를 보낼 프래그먼트의 newInstance 함수의 인자에 전달한다. (위의 과정과 유사하다)
그리고 나서 가장 핵심은 그 아래의 코드이다. 프래그먼트에서 프래그먼트로 데이터를 전달할 때는 아래의 코드를 작성해야한다. (해당 코드를 뜯어보는건 나중에 여유될 때, 또는 응용이 필요해서 이해가 필요할 때 추가해볼 예정이다... 모든걸 한번에 작성하기는 힘드니🥲)
이후 해당 데이터를 받은 SecondFragment의 코틀린 코드에서는 1번과 같은 방식으로 onViewCreated 함수에서 원하는 위젯에 param1 값을 설정하면 된다! 중요한건 위에 코드에 주석으로 처리된 핵심 코드!
Fragment → Activity (인터페이스 구현)
Activity에서 Fragment로 데이터를 넘기는 것과 달리 그 반대 과정은 생각보다 까다롭다.
왜냐하면, 뭐든 간에 Fragment로 데이터를 넘길때는 fragment 내부안에 있는 companion object로 선언된 newInstance 함수를 쓰면 되지만, 액티비티에는 그런 함수가 기본적으로 존재하지 않는다. 따라서, 뭘 통해서 액티비티로 데이터를 넘겨줄 것이냐?
이때는 인터페이스(interface)가 필요하다.
인터페이스 생성 과정 // FragmentDataListener.kt interface FragmentDataListener { fun onDataReceived(data:String) }
정의상 인터페이스 안에는 함수명만 존재하며, 실제 구현체는 해당 인터페이스를 상속받은 클래스 내에 정의된다.
이후엔 프래그먼트로부터 데이터를 전달받을 액티비티에 해당 인터페이스를 상속해야 한다.
// MainActivity.kt class MainActivity : AppCompatActivity(), FragmentDataListener { .. }
그리고 인터페이스를 상속받았으니 그다음엔 뭘 해야한다? 바로 인터페이스 내의 함수를 정의해야 한다.
// MainAcitivity.kt override fun onDataReceived(data: String) { // fragment 에서 받은 데이터를 처리 Toast.makeText(this@MainActivity, data, Toast.LENGTH_SHORT).show() }
fragment 에서 받는 데이터는 꼭 Toast 형태가 아니여도 된다. 뷰 위젯에 데이터를 설정하는 등등.. 이 부분은 원하는 대로 해주면 된다!
이제는 데이터를 전달할 프래그먼트를 살펴봐야 한다.
// SecondFragment.kt private var listener: FragmentDataListener? = null
일단 인터페이스 객체를 생성한다.
// SecondFragment.kt override fun onAttach(context: Context) { super.onAttach(context) Log.d("context", context.toString()) if(context is FragmentDataListener) { listener = context // listener을 해당 액티비티(인터페이스가 구현된)에 할당함 } else { throw RuntimeException("$context must implement FragmentDataListener") } }
이 경우에는 onAttach 함수를 오버라이딩 해야 한다. fragment와 activity를 연결시켜 주고, 위에 변수를 선언한 이유가 여기에 있다.
context는 해당 프래그먼트와 연결된 액티비티를 의미한다.
if문에 context is FragmentDataListener 라는 의미는, 해당 인터페이스 함수가 구현되어 있는지를 말하는 거고
MainActivity는 구현되어 있기 때문에 true를 반환한다.
이후 listener 객체와 context(@MainActivity)를 연결시켜준다.
// SecondFragment.kt override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) binding.btn.setOnClickListener { val dataToSend = "Hello Activity From Fragment!" listener?.onDataReceived(dataToSend) // 중요 } }
이후 onViewCreated 함수에서 데이터를 설정해주고, listener 인터페이스 객체의 함수에 해당 데이터를 넣어주면 된다!
그러면, 그 함수가 구현된 MainActivity에서 데이터를 받아와서 실행된다!
'Android' 카테고리의 다른 글
프래그먼트 생명주기 (0) 2024.04.24 개인 과제 트러블 슈팅(프래그먼트 트랜잭션) (0) 2024.04.22 [Android] RecyclerView (0) 2024.04.15 [과제] 스탠다드반 3주차 특별과제 정리 (0) 2024.04.12 [Android] 뷰 바인딩(View Binding) (0) 2024.04.11