액티비티에서 프래그먼트로 데이터를 전달할 때는, 프래그먼트의 인스턴스를 생성하고 newInstance 메소드를 통해 데이터를 전달함. Bundle 객체를 사용하여 데이터를 프래그먼트의 인자(arguments)로 설정하고, 이 인자를 프래그먼트가 받아 사용함
Fragment1Btn 클릭 리스너 안에서 FirstFragment의 인스턴스를 생성하고, newInstance 메소드에 데이터를 전달하여 프래그먼트를 설정(set). Fragment2Btn에 대해서도 동일한 방법으로 SecondFragment에 데이터를 전달
binding.run {
fragment1Btn.setOnClickListener{
// [1] Activity -> FirstFragment
val dataToSend = "Hello First Fragment! \n From Activity"
val fragment = FirstFragment.newInstance(dataToSend)
setFragment(fragment)
}
fragment2Btn.setOnClickListener {
// [1] Activity -> SecondFragment
val dataToSend = "Hello Second Fragment!\n From Activity"
val fragment = SecondFragment.newInstance(dataToSend)
setFragment(fragment)
}
newInstance 메소드에서 전달받은 데이터를 Bundle에 담고, 프래그먼트의 인자로 설정. onViewCreated에서는 인자로 받은 데이터를 텍스트 뷰에 설정
private var param1: String? = null
companion object {
@JvmStatic
fun newInstance(param1: String) =
// [1] Activity -> FirstFragment
FirstFragment().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
}
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// [1] Activity -> FirstFragment
binding.tvFrag1Text.text = param1
}
실행화면
한 프래그먼트에서 다른 프래그먼트로 데이터를 전달할 때는, 첫 번째 프래그먼트에서 두 번째 프래그먼트의 newInstance 메소드를 사용하여 인스턴스를 생성하고, 데이터를 전달
버튼 클릭 시 SecondFragment의 새 인스턴스를 생성하고, newInstance 메소드를 사용하여 데이터를 전달한 후 프래그먼트 트랜잭션을 통해 두 번째 프래그먼트를 시작
// [2] Fragment -> Fragment
binding.btnGofrag2.setOnClickListener{
val dataToSend = "Hello Fragment2! \n From Fragment1"
val fragment2 = SecondFragment.newInstance(dataToSend)
requireActivity().supportFragmentManager.beginTransaction()
.replace(R.id.frameLayout, fragment2)
.addToBackStack(null)
.commit()
}
newInstance 메소드로 전달받은 데이터를 Bundle에 담고, onCreate 또는 onViewCreated에서 Bundle로부터 데이터를 추출하여 사용
private const val ARG_PARAM1 = "param1"
class SecondFragment : Fragment() {
private var param1: String? = null
private var _binding: FragmentSecondBinding? = null
private val binding get() = _binding!!
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
param1 = it.getString(ARG_PARAM1)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentSecondBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// [2] Fragment -> Fragment
binding.tvFrag2Text.text = param1
}
companion object {
@JvmStatic
fun newInstance(param1: String) =
// [1] Activity -> FirstFragment
SecondFragment().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
}
}
}
override fun onDestroyView() {
super.onDestroyView()
// Binding 객체 해제
_binding = null
}
}
실행화면
프래그먼트에서 액티비티로 데이터를 전달할 때는 콜백 인터페이스를 정의하고, 해당 인터페이스를 액티비티가 구현하도록 함. 프래그먼트는 이 인터페이스를 사용하여 액티비티에 데이터를 전달
FragmentDataListener 인터페이스를 정의하고, 프래그먼트가 액티비티에 붙을 때 (onAttach) 액티비티가 이 인터페이스를 구현했는지 확인. 버튼 클릭 리스너에서 onDataReceived 메소드를 호출하여 데이터를 액티비티에 전달
private const val ARG_PARAM1 = "param1"
interface FragmentDataListener {
fun onDataReceived(data: String)
}
class SecondFragment : Fragment() {
// [3] SecondFragment -> Activity
private var listener: FragmentDataListener? = null
private var param1: String? = null
private var _binding: FragmentSecondBinding? = null
private val binding get() = _binding!!
override fun onAttach(context: Context) {
super.onAttach(context)
// [3] SecondFragment -> Activity
if (context is FragmentDataListener) {
listener = context
} else {
throw RuntimeException("$context must implement FragmentDataListener")
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
param1 = it.getString(ARG_PARAM1)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentSecondBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// [2] Fragment -> Fragment
binding.tvFrag2Text.text = param1
// [3] SecondFragment -> Activity
binding.btnSendActivity.setOnClickListener{
val dataToSend = "Hello from SecondFragment!"
listener?.onDataReceived(dataToSend)
}
}
companion object {
@JvmStatic
fun newInstance(param1: String) =
// [1] Activity -> FirstFragment
SecondFragment().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
}
}
}
override fun onDestroyView() {
super.onDestroyView()
// Binding 객체 해제
_binding = null
listener = null
}
}
MainActivity는 FragmentDataListener 인터페이스를 구현하고, onDataReceived 메소드를 오버라이드하여 프래그먼트로부터 데이터를 받음. 데이터를 받으면 Toast 메시지로 표시
class MainActivity : AppCompatActivity(), FragmentDataListener {
private val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
binding.apply {
fragment1Btn.setOnClickListener{
// [1] Activity -> FirstFragment
val dataToSend = "Hello First Fragment! \n From Activity"
val fragment = FirstFragment.newInstance(dataToSend)
setFragment(fragment)
}
fragment2Btn.setOnClickListener {
// [1] Activity -> SecondFragment
val dataToSend = "Hello Second Fragment!\n From Activity"
val fragment = SecondFragment.newInstance(dataToSend)
setFragment(fragment)
}
}
setFragment(FirstFragment())
}
private fun setFragment(frag : Fragment) {
supportFragmentManager.commit {
replace(R.id.frameLayout, frag)
setReorderingAllowed(true)
addToBackStack("")
}
}
// [3] SecondFragment -> Activity
override fun onDataReceived(data: String) {
// Fragment에서 받은 데이터를 처리
Toast.makeText(this, data, Toast.LENGTH_SHORT).show()
}
}
실행화면