안드로이드 코틀린 : Fragment에서 Fragment 생성 및 데이터 보내기
Lucy Archive
Lucy 2023
2021. 3. 30. 00:37

Android Kotlin : 프래그먼트에서 프래그먼트에 데이터 보내기(작업 요청하기)

지난 포스트에서는 Activity에서 Fragment 생성시 또는 생성된 Fragment에 데이터를 전송하는 방법에 대해 소개하였습니다. 이번 포스트는

Fragment에서 다른 Fragment를 호출하거나 데이터를 보내는 방법

에 대해 소개합니다. Fragment와 관련된 지난 포스트는 아래의 링크에 남겨 놓았습니다.

Fragment : 추가, 변경, 삭제

 

안드로이드 코틀린 : Fragment 추가, 변경, 삭제 사용법 및 유의점

Android Kotlin : Activity에 Fragmeent 추가, 변경, 삭제 및 고려사항 정리 안드로이드 개발자 가이드에서는 (다양한 이유로) 다수의 화면을 포함하는 앱은 다수의 Activity가 아닌 Fragment 사용하길 권장합니

juahnpop.tistory.com

Activity에서 Fragment에 데이터 전달 : Fragment 생성시 및 생성된 Fragment

 

안드로이드 코틀린 : Activity에서 Fragment에 데이터 보내기

Android Kotlin : Fragment 데이터 전달 및 상호 작용 지난 포스트에서는 Fragment 생성, 변경, 삭제와 같은 전환 방법에 대해 작성하였습니다. 이번 포스트는 Activity에서 Fragment 생성시 또는 생성되어 있는

juahnpop.tistory.com

 

프로젝트 생성 및 환경 설정

프로젝트 생성

아래 그림과 같이 프로젝트를 생성합니다.

  • 프로젝트명 : 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 설정 코드 추가 및 적용

※ ViewBinding 은 Layout 에 있는 View의 Id를 코틀린 코드에서 직접 사용 할 수 있게 해주는 도구입니다. View Binding과 관련된 설명은 아래의 링크를 참조해주세요.

안드로이드 View Binding 사용하기

 

안드로이드 View Binding 사용하기 - kotlin-android-extensions 지원 중단

안드로이드 View Binding 방법 정리 안드로이드 코드에서 레이아웃 View에 접근하기 위해 사용된 kotlin-android-extensions 의 지원이 중단예정으로, 이를 대체하여 사용 할 수 있는 ViewBinding 사용법에 대해

juahnpop.tistory.com

 

Fragment 에서 Fragment 추가

Fragment 추가

아래 그림과 같이 FragmentA 란 이름의 Fragment를 추가합니다. Fragment 가 추가되면 아래와 같이 FragmentA.kt 코틀린 파일과 fragment_a.xml 레이아웃 파일이 생성됩니다. 같은 방법으로 FragmentB 와 FragmentC를 추가합니다.

Fragment 추가하기

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 화면은 아래와 같습니다.

activity_main.xml, fragment_a.xml, fragment_b.xml, fragment_c.xml

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 추가하기

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

 

안드로이드 코틀린 : AlertDialog 기본, 목록, 라디오 버튼, 체크 박스, EditText 입력 창

안드로이드 코틀린 : AlertDialog 기본, 목록, 체크박스 목록, 라디오 버튼 목록, 입력(Edit Text) 사용법 이번 포스트는 안드로이드 코틀린 언어를 사용하여 AlertDialog를 활용한 기본 사용 방법, 목록 선

juahnpop.tistory.com

 

FragmentB.kt 코드 추가

FragmentB.kt 파일에 아래의 setText() 메서드를 등록합니다. FragmentA로 부터 MainActivity의 changeText() 메서드가 호출되면 실행되는 메서드로 FragmentB 내부 TextView의 문자열을 변경합니다.

fun setText(string:String){
    binding.textView.text = string
}

실행 결과

위 코드를 수정 후 앱을 실행하면 아래와 같이 생성된 fragmentB의 textView에 문자열이 변경 되는 것을 확인 할 수 있습니다. 

Fragment에서 Fragment에 데이터 전송

끝까지 읽어 주셔서 감사합니다.^^

정리

Activity는 Fragment에서 Fragment에 데이터를 전달을 위한 매개체로 사용한다.

  • FragmentA에서 Acitvity로 작업 요청(데이터 전달)
  • Activity에서 FragmentB에게 작업 요청(데이터 전달)
관련포스트

🤞 안드로이드(코틀린) 앱 제작하기 관련글 목록 보기

🤞 안드로이드(코틀린) 프래그먼트 관련글 목록 보기