[Kotlin] Fragment에서 Child Fragment로 데이터 전달
1. Interface를 이용하는 방법
2. Bundle 객체를 생성해서 Fragment의 전달인자로 보내는 방법
3. requireActivity()를 전달인자로 사용한 ViewModel을 공유하는 방법
4. requireParentFragment()를 전달인자로 사용한 ViewModel을 공유하는 방법
1. Interface를 이용하는 방법
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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"
android:paddingBottom="40dp"
android:paddingRight="40dp"
android:paddingLeft="40dp"
android:orientation="vertical"
android:gravity="center"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginBottom="20dp"
android:textAllCaps="false"
android:textSize="22dp"
android:text="MainActivity Area"
android:textStyle="bold|italic"/>
<FrameLayout
android:id="@+id/frameLayoutParent"
android:layout_width="match_parent"
android:background="#DDDDDD"
android:layout_height="0dp"
android:layout_weight="1"/>
</LinearLayout>
fragment_parent.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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:paddingLeft="40dp"
android:paddingRight="40dp"
android:paddingBottom="40dp"
android:orientation="vertical"
android:gravity="center">
<TextView
android:id="@+id/tvParent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:textAllCaps="false"
android:text="ParentFragment Area"
android:textSize="20dp"
android:textStyle="bold|italic"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
<Button
android:id="@+id/btnParent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginBottom="20dp"
android:textAllCaps="false"
android:text="Parent -> Child"/>
<FrameLayout
android:id="@+id/frameLayoutChild"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#BBBBBB"/>
</LinearLayout>
fragment_child.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="top|center">
<TextView
android:id="@+id/tvChild"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:textAllCaps="false"
android:text="ChildFragment Area"
android:textSize="18dp"
android:textStyle="bold|italic"/>
<Button
android:id="@+id/btnChild"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:textAllCaps="false"
android:text="Child -> Parent"/>
</LinearLayout>
FragmentListener.kt
package com.jwsoft.kotlinproject
interface FragmentListener {
fun onReceivedData(data: String)
}
MainActivity.kt
package com.jwsoft.kotlinproject
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
var transaction = supportFragmentManager.beginTransaction()
transaction.add(R.id.frameLayoutParent, FragmentParent()).commit()
}
}
FragmentParent.kt
package com.jwsoft.kotlinproject
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import kotlinx.android.synthetic.main.fragment_parent.*
class FragmentParent : Fragment(), FragmentListener {
private lateinit var mFragmentListener: FragmentListener
private var fragmentChild = FragmentChild()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_parent, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val transaction = childFragmentManager.beginTransaction()
transaction.add(R.id.frameLayoutChild, fragmentChild).commit()
btnParent.setOnClickListener {
mFragmentListener = fragmentChild
mFragmentListener.onReceivedData("Parent -> Child")
}
}
override fun onReceivedData(data: String) {
tvParent.text = data
}
}
FragmentChild.kt
package com.jwsoft.kotlinproject
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import kotlinx.android.synthetic.main.fragment_child.*
class FragmentChild : Fragment(), FragmentListener {
private lateinit var mFragmentListener: FragmentListener
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_child, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
btnChild.setOnClickListener {
mFragmentListener = parentFragment as FragmentParent
mFragmentListener.onReceivedData("Child -> Parent")
}
}
override fun onReceivedData(data: String) {
tvChild.text = data
}
}
2. Bundle 객체를 이용하는 방법
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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"
android:paddingBottom="40dp"
android:paddingRight="40dp"
android:paddingLeft="40dp"
android:orientation="vertical"
android:gravity="center"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginBottom="20dp"
android:textAllCaps="false"
android:textSize="22dp"
android:text="MainActivity Area"
android:textStyle="bold|italic"/>
<FrameLayout
android:id="@+id/frameLayoutParent"
android:layout_width="match_parent"
android:background="#DDDDDD"
android:layout_height="0dp"
android:layout_weight="1"/>
</LinearLayout>
fragment_parent.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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:paddingLeft="40dp"
android:paddingRight="40dp"
android:paddingBottom="40dp"
android:orientation="vertical"
android:gravity="center">
<TextView
android:id="@+id/tvParent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:textAllCaps="false"
android:text="ParentFragment Area"
android:textSize="20dp"
android:textStyle="bold|italic"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
<Button
android:id="@+id/btnParent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginBottom="20dp"
android:textAllCaps="false"
android:text="Parent -> Child"/>
<FrameLayout
android:id="@+id/frameLayoutChild"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#BBBBBB"/>
</LinearLayout>
fragment_child.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="top|center">
<TextView
android:id="@+id/tvChild"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:textAllCaps="false"
android:text="ChildFragment Area"
android:textSize="18dp"
android:textStyle="bold|italic"/>
<Button
android:id="@+id/btnChild"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:textAllCaps="false"
android:visibility="gone"
android:text="Child -> Parent"/>
</LinearLayout>
MainActivity.kt
package com.jwsoft.kotlinproject
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
var transaction = supportFragmentManager.beginTransaction()
transaction.add(R.id.frameLayoutParent, FragmentParent()).commit()
}
}
FragmentParent.kt
package com.jwsoft.kotlinproject
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import kotlinx.android.synthetic.main.fragment_parent.*
class FragmentParent : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_parent, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
btnParent.setOnClickListener {
val bundle = Bundle().apply { putString("data", "Parent -> Child") }
val fragmentChild = FragmentChild().apply { arguments = bundle }
val transaction = childFragmentManager.beginTransaction()
transaction.add(R.id.frameLayoutChild, fragmentChild).commit()
}
}
}
FragmentChild.kt
package com.jwsoft.kotlinproject
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import kotlinx.android.synthetic.main.fragment_child.*
class FragmentChild : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_child, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val bundle = arguments
tvChild.text = bundle!!.getString("data")
}
}
3. requireActivity()를 전달인자로 사용한 ViewModel을 공유하는 방법
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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"
android:paddingBottom="40dp"
android:paddingRight="40dp"
android:paddingLeft="40dp"
android:orientation="vertical"
android:gravity="center"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginBottom="20dp"
android:textAllCaps="false"
android:textSize="22dp"
android:text="MainActivity Area"
android:textStyle="bold|italic"/>
<FrameLayout
android:id="@+id/frameLayoutParent"
android:layout_width="match_parent"
android:background="#DDDDDD"
android:layout_height="0dp"
android:layout_weight="1"/>
</LinearLayout>
fragment_parent.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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:paddingLeft="40dp"
android:paddingRight="40dp"
android:paddingBottom="40dp"
android:orientation="vertical"
android:gravity="center">
<TextView
android:id="@+id/tvParent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:textAllCaps="false"
android:text="ParentFragment Area"
android:textSize="20dp"
android:textStyle="bold|italic"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
<Button
android:id="@+id/btnParent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginBottom="20dp"
android:textAllCaps="false"
android:text="Parent -> Child"/>
<FrameLayout
android:id="@+id/frameLayoutChild"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#BBBBBB"/>
</LinearLayout>
fragment_child.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="top|center">
<TextView
android:id="@+id/tvChild"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:textAllCaps="false"
android:text="ChildFragment Area"
android:textSize="18dp"
android:textStyle="bold|italic"/>
<Button
android:id="@+id/btnChild"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:textAllCaps="false"
android:text="Child -> Parent"/>
</LinearLayout>
ActivityViewModel.kt
package com.jwsoft.kotlinproject
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
class ActivityViewModel : ViewModel() {
var fragmnetParentText: MutableLiveData<String> = MutableLiveData()
var fragmentchildText: MutableLiveData<String> = MutableLiveData()
}
MainActivity.kt
package com.jwsoft.kotlinproject
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
var transaction = supportFragmentManager.beginTransaction()
transaction.add(R.id.frameLayoutParent, FragmentParent()).commit()
}
}
FragmentParent.kt
package com.jwsoft.kotlinproject
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import kotlinx.android.synthetic.main.fragment_parent.*
class FragmentParent : Fragment() {
private lateinit var viewModel: ActivityViewModel
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
viewModel = ViewModelProvider(requireActivity(), ViewModelProvider.NewInstanceFactory())
.get(ActivityViewModel::class.java)
return inflater.inflate(R.layout.fragment_parent, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val transaction = fragmentManager!!.beginTransaction()
transaction.add(R.id.frameLayoutChild, FragmentChild()).commit()
btnParent.setOnClickListener {
viewModel.fragmentchildText.value = "Parent -> Child"
}
viewModel.fragmnetParentText.observe(this, Observer {
tvParent.text = it
})
}
}
FragmentChild.kt
package com.jwsoft.kotlinproject
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import kotlinx.android.synthetic.main.fragment_child.*
class FragmentChild : Fragment() {
private lateinit var viewModel: ActivityViewModel
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
viewModel = ViewModelProvider(requireActivity(), ViewModelProvider.NewInstanceFactory())
.get(ActivityViewModel::class.java)
return inflater.inflate(R.layout.fragment_child, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
btnChild.setOnClickListener {
viewModel.fragmnetParentText.value = "Child -> Parent"
}
viewModel.fragmentchildText.observe(this, Observer {
tvChild.text = it
})
}
}
4. requireParentFragment()를 전달인자로 사용한 ViewModel을 공유하는 방법
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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"
android:paddingBottom="40dp"
android:paddingRight="40dp"
android:paddingLeft="40dp"
android:orientation="vertical"
android:gravity="center"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginBottom="20dp"
android:textAllCaps="false"
android:textSize="22dp"
android:text="MainActivity Area"
android:textStyle="bold|italic"/>
<FrameLayout
android:id="@+id/frameLayoutParent"
android:layout_width="match_parent"
android:background="#DDDDDD"
android:layout_height="0dp"
android:layout_weight="1"/>
</LinearLayout>
fragment_parent.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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:paddingLeft="40dp"
android:paddingRight="40dp"
android:paddingBottom="40dp"
android:orientation="vertical"
android:gravity="center">
<TextView
android:id="@+id/tvParent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:textAllCaps="false"
android:text="ParentFragment Area"
android:textSize="20dp"
android:textStyle="bold|italic"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
<Button
android:id="@+id/btnParent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginBottom="20dp"
android:textAllCaps="false"
android:text="Parent -> Child"/>
<FrameLayout
android:id="@+id/frameLayoutChild"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#BBBBBB"/>
</LinearLayout>
fragment_child.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="top|center">
<TextView
android:id="@+id/tvChild"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:textAllCaps="false"
android:text="ChildFragment Area"
android:textSize="18dp"
android:textStyle="bold|italic"/>
<Button
android:id="@+id/btnChild"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:textAllCaps="false"
android:text="Child -> Parent"/>
</LinearLayout>
FragmentViewModel.kt
package com.jwsoft.kotlinproject
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
class FragmentViewModel : ViewModel() {
var fragmnetParentText: MutableLiveData<String> = MutableLiveData()
var fragmentchildText: MutableLiveData<String> = MutableLiveData()
}
MainActivity.kt
package com.jwsoft.kotlinproject
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
var transaction = supportFragmentManager.beginTransaction()
transaction.add(R.id.frameLayoutParent, FragmentParent()).commit()
}
}
FragmentParent.kt
package com.jwsoft.kotlinproject
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import kotlinx.android.synthetic.main.fragment_parent.*
class FragmentParent : Fragment() {
private lateinit var viewModel: FragmentViewModel
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
viewModel = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory())
.get(FragmentViewModel::class.java)
return inflater.inflate(R.layout.fragment_parent, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// fragmentManager 사용하면 안됨
val transaction = childFragmentManager.beginTransaction()
transaction.add(R.id.frameLayoutChild, FragmentChild()).commit()
btnParent.setOnClickListener {
viewModel.fragmentchildText.value = "Parent -> Child"
}
viewModel.fragmnetParentText.observe(this, Observer {
tvParent.text = it
})
}
}
val transaction = fragmentManager!!.beginTransaction() -> X
val transaction = childFragmentManager.beginTransaction() -> O
FragmentChild.kt
package com.jwsoft.kotlinproject
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import kotlinx.android.synthetic.main.fragment_child.*
class FragmentChild : Fragment() {
private lateinit var viewModel: FragmentViewModel
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
viewModel = ViewModelProvider(requireParentFragment(), ViewModelProvider.NewInstanceFactory())
.get(FragmentViewModel::class.java)
return inflater.inflate(R.layout.fragment_child, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
btnChild.setOnClickListener {
viewModel.fragmnetParentText.value = "Child -> Parent"
}
viewModel.fragmentchildText.observe(this, Observer {
tvChild.text = it
})
}
}
requireParentFragment() 사용