안드로이드 코틀린 : Activity에서 Fragment에 데이터 보내기
Lucy Archive
Lucy 2023
2021. 3. 25. 23:46

Android Kotlin : Fragment 데이터 전달 및 상호 작용

지난 포스트에서는 Fragment 생성, 변경, 삭제와 같은 전환 방법에 대해 작성하였습니다. 이번 포스트는

Activity에서 Fragment 생성시 또는 생성되어 있는 Fragment에 데이터를 전송하는 방법에 대해 소개

합니다. Fragment의 기본적인 생성, 변경, 삭제는 아래의 링크를 참고해주세요.

Fragment 추가, 변경, 삭제

 

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

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

juahnpop.tistory.com

 

프로젝트 생성 환경설정

프로젝트 생성

  • 프로젝트명 : FragmentData
  • 사용언어 : Kotlin

프로젝트 생성

※ Android Studio 버전 : 4.1.2

 

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

 

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

Fragment 추가

아래 그림과 같이 FragmentA 란 이름의 Fragment를 추가합니다. Fragment 가 추가되면 아래와 같이 FragmentA.kt 파일과 fragment_a.xml 파일이 생성됩니다. 

Fragment 추가

activity_main.xml 코드 작성

우선 activity_main.xml 의 코드를 아래와 같이 작성합니다. Button을 클릭하면 FragmentA를 FrameLayout에 표시할 예정입니다.

<?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/frameLayout"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_margin="8dp"
        app:layout_constraintBottom_toTopOf="@+id/button"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />    
    
    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Get fragment"
        android:layout_margin="8dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />
    
</androidx.constraintlayout.widget.ConstraintLayout>

생성된 UI

fragment_a.xml 코드 작성

fragment_a.xml 안 아래와 같이 코드를 작성합니다. 텍스트 뷰 하나만 가지고 있는 Fragment 입니다.

<?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="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_blank_fragment"
        android:textSize="22dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

MainActivity.kt 코드 작성

MainActivity.kt 의 코드는 아래와 같이 작성합니다. Activity 에서 Fragment 추가시 데이터를 넘기기 위해 Bundle() 클래스 객체에 데이터를 입력 후 fragmentA의 arguments 프로퍼티에 생성한 Bundle() 클래스 객체를 입력 후,  프래그먼트 메니저를 통해 안드로이드에 fragmentA 생성을 요청합니다. 

🧨 Bundle은 Map타입과 같이 Key, Data 쌍으로 데이터 저장이 가능합니다. 아래 코드에서는 문자열을 저장하기 위해 putString() 메서드를 사용하였지만, 데이터 타입에 따라 putInt(), putDouble() 과 같이 다양한 메서드가 있습니다.

🧨 arguments 프로퍼티는 Fragment 클래스에서 기본적으로 제공되는 프로퍼티 입니다.

package com.blacklog.fragmentdata

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.blacklog.fragmentdata.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {

    lateinit var binding : ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        val view = binding.root
        setContentView(view)

        binding.button.setOnClickListener {
            val bundle = Bundle()
            bundle.putString("Key", "Hello FragmentA")

            val fragmentA = FragmentA()
            fragmentA.arguments = bundle

            val transaction = supportFragmentManager.beginTransaction()
            transaction.add(R.id.frameLayout, fragmentA)
            transaction.commit()
        }
    }
}

 

FragmentA.kt 코드 작성

처음 FragmentA.kt 코드를 열면 코드가 많은데, 처음에 코드가 많으면 정신이 없으니 onCreateView() 만 남기고 나머지 코드는 삭제 후 아래와 같이 코드를 작성합니다. ViewBinding 과 관련된 코드는 상단의 ViewBinding 관련 링크를 참조해주세요.

Activity에서 Fragment 생성시 argument에 저장된 데이터는, Fragment 코드 내에서 argument 에서 바로 사용 할 수 있습니다. argument는 getArgument() 함수의 결과 값입니다. 

package com.blacklog.fragmentdata

import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.blacklog.fragmentdata.databinding.FragmentABinding

class FragmentA : Fragment() {

    private var _binding : FragmentABinding? = null
    private val binding get() = _binding!!

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        _binding = FragmentABinding.inflate(inflater, container, false)
        binding.textView.text = arguments?.getString("Key")
        return binding.root
    }
}

🧩 Fragment에서 onCreateView()는 프래그먼트가 UI를 표시할 때 호출 되는 함수입니다. 최종적으로 표시되는 UI는 함수 마지막에 return 되는 값입니다. 좀 더 자세히 알고 싶으신 분은 'Fragment 생명 주기' 란 단어로 검색하시면 자세한 내용을 볼 수 있습니다. 저는 이후에 따로 정리할 예정입니다.

실행 결과

위 코드를 작성 후 실행하면 MainActivity 에서 Fragment의 argument에 저장한 "Hello FragmentA" 문자열이 Fragment의 TextView에 표시되는 것을 확인 할 수 있습니다.

Fragment 생성시 데이터 전달

 

Activity에서 이미 생성된 Fragment 에 데이터 전달

위 프로그램에서 이미 생성된 FragmentA의 TextView의 문자열 변경하기 위해 아래와 같은 추가 작업을 진행합니다.

activity_main.xml 수정

activity_main.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=".MainActivity">

    <FrameLayout
        android:id="@+id/frameLayout"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_margin="8dp"
        app:layout_constraintBottom_toTopOf="@+id/button"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/button"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_margin="8dp"
        android:text="Show Fragment"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/button2"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent" />

    <Button
        android:id="@+id/button2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Send Data"
        android:layout_margin="8dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/button" />

</androidx.constraintlayout.widget.ConstraintLayout>

생성된 UI는 아래 그림과 같습니다. SHOW FRAGMENT를 누르면 FragmentA 가 FrameLayout에 연결되고, SEND DATA 버튼을 누르면 실행된 FRAGMENT의 TextView의 문자열 변경 할 예정입니다.

activity_main.xml 레이아웃

FragmentA.kt 코드 수정

Activity에서 실행된 Fragment에 데이터를 보내고 싶은 경우 Fragment 클래스에 메서드를 등록하고, Activity에서 Fragment에 등록된 메서드를 호출 하는 방법을 사용합니다. 반대로 Fragment에서 Activity에 데이터를 보내기 위해(또는 작업을 요청하기 위해) 같은 방법을 사용 할 수 있습니다. 

아래와 같이 FragmentA.kt 에 changeTextView() 메서드를 등록합니다.

package com.blacklog.fragmentdata

import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.blacklog.fragmentdata.databinding.FragmentABinding

class FragmentA : Fragment() {

    private var _binding : FragmentABinding? = null
    private val binding get() = _binding!!

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        _binding = FragmentABinding.inflate(inflater, container, false)
        binding.textView.text = arguments?.getString("Key")
        return binding.root
    }

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

MainActivity.kt 코드 수정

MainActivity.kt 코드는 아래와 같이 추가된 버튼 리스너를 등록하고, 추가된 버튼에서 생성되어 있는 fragment에 접근하기 위해 val flagmentA = Fragment() 코드의 위치를 변경합니다.

package com.blacklog.fragmentdata

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.blacklog.fragmentdata.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {

    lateinit var binding : ActivityMainBinding


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        val view = binding.root
        setContentView(view)

        val fragmentA = FragmentA()

        binding.button.setOnClickListener {
            val bundle = Bundle()
            bundle.putString("Key", "Hello FragmentA")

            fragmentA.arguments = bundle

            val transaction = supportFragmentManager.beginTransaction()
            transaction.add(R.id.frameLayout, fragmentA)
            transaction.commit()
        }

        binding.button2.setOnClickListener {
            fragmentA.changeTextView("Hi~! FragmentA :)")
        }
    }
}

실행 결과

위 코드를 작성 후 실행하면 아래와 같이 SEND DATA 버튼을 클릭하면 생성된 Fragment의 TextView가 변경 되는 것을 확인 할 수 있습니다. 

생성된 Fragment에 데이터 전송(작업요청)

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

관련포스트

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

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