Android Kotlin : 프래그먼트에서 프래그먼트에 데이터 보내기(작업 요청하기)
Fragment에서 다른 Fragment를 호출하거나 데이터를 보내는 방법
에 대해 소개합니다. Fragment와 관련된 지난 포스트는 아래의 링크에 남겨 놓았습니다.Activity에서 Fragment에 데이터 전달 : Fragment 생성시 및 생성된 Fragment
프로젝트 생성 및 환경 설정
프로젝트 생성
아래 그림과 같이 프로젝트를 생성합니다.
- 프로젝트명 : Fragment
- 사용언어 : Kotlin
※ 이 포스트에서 사용한 개발 환경은 아래와 같습니다.
- Android Studio 4.1.2
- Kotlin Version 1.4.31
ViewBinding 설정
build.gradle(Module: ManagingFolder) 파일에 아래의 ViewBinding 설정 코드를 추가합니다.
android {
...
viewBinding {
enabled = true
}
}
코드 추가가 완료되면 아래와 같이 Sync Now 클릭해서 Gradle 변경 사항을 적용합니다.
※ ViewBinding 은 Layout 에 있는 View의 Id를 코틀린 코드에서 직접 사용 할 수 있게 해주는 도구입니다. View Binding과 관련된 설명은 아래의 링크를 참조해주세요.
Fragment 에서 Fragment 추가
Fragment 추가
아래 그림과 같이 FragmentA 란 이름의 Fragment를 추가합니다. Fragment 가 추가되면 아래와 같이 FragmentA.kt 코틀린 파일과 fragment_a.xml 레이아웃 파일이 생성됩니다. 같은 방법으로 FragmentB 와 FragmentC를 추가합니다.
activity_main.xml 코드 작성
activity_main.xml 레이아웃 파일의 코드는 아래와 같이 작성하였습니다. FrameLayoutA는 FragmentA를 불러오고, FragmentA에서 FrameLayoutB에 FragmentB 또는 FragmentC를 호출 할 예정입니다.
<?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/frameLayoutA"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="#33003300"
app:layout_constraintBottom_toTopOf="@+id/textView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHeight_percent="0.45"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:text="frameLayoutA"
android:gravity="center"
app:layout_constraintBottom_toTopOf="@+id/frameLayoutB"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHeight_percent="0.05"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/frameLayoutA" />
<FrameLayout
android:id="@+id/frameLayoutB"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="#33330000"
app:layout_constraintBottom_toTopOf="@+id/textView2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHeight_percent="0.45"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView" />
<TextView
android:id="@+id/textView2"
android:layout_width="match_parent"
android:layout_height="0dp"
android:text="frameLayoutB"
android:gravity="center"
app:layout_constraintBottom_toTopOf="@+id/frameLayoutB"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHeight_percent="0.05"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/frameLayoutB" />
</androidx.constraintlayout.widget.ConstraintLayout>
fragment_a.xml ~ fragment_c.xml 코드 작성
fragment_a.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=".FragmentA">
<!-- TODO: Update blank fragment layout -->
<TextView
android:id="@+id/textView"
android:layout_width="0dp"
android:layout_height="match_parent"
android:text="FragmentA"
android:gravity="center"
android:layout_margin="8dp"
app:layout_constraintWidth_percent="0.55"
app:layout_constraintEnd_toStartOf="@+id/btnShowFragmentB"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:id="@+id/btnShowFragmentB"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Show FragmentB"
android:layout_margin="8dp"
app:layout_constraintWidth_percent="0.4"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/btnChaneTextFragmentB"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Change Text in FragmentB"
android:layout_margin="8dp"
app:layout_constraintWidth_percent="0.4"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btnShowFragmentB" />
<Button
android:id="@+id/btnShowFragmentC"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Show FragmentC"
android:layout_margin="8dp"
app:layout_constraintWidth_percent="0.4"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
fragment_b.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=".FragmentB">
<!-- TODO: Update blank fragment layout -->
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="I am Fragment B"
android:textSize="22sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
fragment_c.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=".FragmentC">
<!-- TODO: Update blank fragment layout -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="I am Fragment C"
android:textSize="22sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />" />
</androidx.constraintlayout.widget.ConstraintLayout>
생성된 UI 화면은 아래와 같습니다.
MainActivity.kt 코드 작성
MainActivity.kt 코드는 아래와 같이 작성합니다. 코드의 주요 기능은 두가지 입니다.
- onCreate() : 액티비티 생성시 frameLayoutA에 FragmentA를 추가
- openFragmentOnFrameLayoutB() : FragmentA에서 frameLayoutB에 Fragment를 추가하기 위해 생성된 메서드
package com.blacklog.fragment
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.FrameLayout
import android.widget.Toast
import androidx.fragment.app.Fragment
import com.blacklog.fragment.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private val fragmentA = FragmentA()
private var fragmentB = FragmentB()
private var fragmentC = FragmentC()
lateinit var binding : ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
// frameLayoutA 에 FragmentA 로드하기
val transaction = supportFragmentManager.beginTransaction()
.replace(R.id.frameLayoutA, fragmentA)
transaction.commit()
}
// fragmentA 에서 frameLayoutB에 fragment 추가하기 위해 호출 하는 메서드
fun openFragmentOnFrameLayoutB(int: Int){
val transaction = supportFragmentManager.beginTransaction()
when(int){
1 -> transaction.replace(R.id.frameLayoutB, fragmentB)
2 -> transaction.replace(R.id.frameLayoutB, fragmentC)
}
transaction.commit()
}
}
FragmentA.kt 코드 작성
FragmentA.kt 에 아래와 같이 코드를 작성합니다. 코드의 주요 내용은 아래와 같습니다.
- MainActivity 클래스의 openFragmentOnFrameLayoutB() 메서드를 사용하기 위한 MainActivity 인스턴스 생성
- 2개의 버튼에 FragmentB와 FragmentC 추가를 위한 리스너 코드 작성
package com.blacklog.fragment
import android.content.Context
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.blacklog.fragment.databinding.FragmentABinding
class FragmentA : Fragment() {
private var _binding : FragmentABinding? = null
private val binding get() = _binding!!
var mainActivity: MainActivity? = null
override fun onAttach(context: Context) {
super.onAttach(context)
mainActivity = context as MainActivity
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentABinding.inflate(inflater, container, false)
binding.btnShowFragmentB.setOnClickListener {
mainActivity!!.openFragmentOnFrameLayoutB(1)
}
binding.btnShowFragmentC.setOnClickListener {
mainActivity!!.openFragmentOnFrameLayoutB(2)
}
return binding.root
}
}
실행 결과
위 코드를 빌드 후 실행하면 아래와 같이 FragmentA의 SHOW FRAGMENTB, SHOW FRAGMENTC 버튼을 누르는 경우 frameLayoutB에 각각 FragmentB와 FragmentC가 로드되는 것을 확인 할 수 있습니다.
Fragment 에서 생성된 Fragment에 데이터 전달
FragmentA의 'CHANGE TEXT IN FRAGMENTB' 버튼을 누르면 FragmentB의 textView 문자열을 변경 하는 기능을 추가합니다.
MainActivity.kt 코드 추가
MainActivity.kt 클래스에 아래의 changeText() 메서드를 추가합니다. FragmentA로 부터 changeText() 메서드가 호출되면 FragmentB.kt 의 setText() 메서드가 동작되도록 코드를 작성합니다. Activity는 Fragment 사이의 중간자 역할을 한다고 보면 됩니다.
fun changeText(string :String){
fragmentB.setText(string)
}
FragmentA.kt 코드 추가
FragmentA.kt 의 onCreateView() 함수 내에 아래의 버튼 리스너 코드를 추가합니다. 텍스트 변경 버튼을 누르면 변경할 문자열 메세지를 선택할 다이얼로그 창을 띄우고, 메세지가 선택되면 MainActivity의 changeText() 메서드를 호출합니다.
binding.btnChaneTextFragmentB.setOnClickListener {
val items = arrayOf("How are you?", "I am fine.")
var selectedItem: String? = null
val builder = AlertDialog.Builder(mainActivity!!)
.setTitle("Select Sentence")
.setSingleChoiceItems(items, -1){ dialogInterface: DialogInterface, i: Int ->
selectedItem = items[i]
}
.setPositiveButton("Select"){ dialogInterface: DialogInterface, i: Int ->
mainActivity!!.changeText(selectedItem!!)
}
builder.show()
}
안드로이드 대화상자(AlertDialog) 사용법은 아래의 링크를 참고해주세요.
AlertDialog 사용법 정리 : 기본, 목록, 라디오 버튼, 체크박스, EditText
FragmentB.kt 코드 추가
FragmentB.kt 파일에 아래의 setText() 메서드를 등록합니다. FragmentA로 부터 MainActivity의 changeText() 메서드가 호출되면 실행되는 메서드로 FragmentB 내부 TextView의 문자열을 변경합니다.
fun setText(string:String){
binding.textView.text = string
}
실행 결과
위 코드를 수정 후 앱을 실행하면 아래와 같이 생성된 fragmentB의 textView에 문자열이 변경 되는 것을 확인 할 수 있습니다.
끝까지 읽어 주셔서 감사합니다.^^
정리
Activity는 Fragment에서 Fragment에 데이터를 전달을 위한 매개체로 사용한다.
- FragmentA에서 Acitvity로 작업 요청(데이터 전달)
- Activity에서 FragmentB에게 작업 요청(데이터 전달)
'Programming > Android App(Kotlin)' 카테고리의 다른 글
안드로이드 코틀린 : RecyclerView로 목록 만들기(with ViewBinding) (2) | 2021.03.31 |
---|---|
안드로이드 코틀린 : Spinner 로 목록 만들기 및 기타 설정 방법 (0) | 2021.03.30 |
안드로이드 코틀린 : Activity에서 Fragment에 데이터 보내기 (0) | 2021.03.25 |
안드로이드 코틀린 : Fragment 추가, 변경, 삭제 사용법 및 유의점 (1) | 2021.03.25 |
안드로이드 코틀린 : Intent 명시적 호출 방법 정리 (0) | 2021.03.25 |