Android Kotlin : Fragment 데이터 전달 및 상호 작용
Activity에서 Fragment 생성시 또는 생성되어 있는 Fragment에 데이터를 전송하는 방법에 대해 소개
합니다. Fragment의 기본적인 생성, 변경, 삭제는 아래의 링크를 참고해주세요.
프로젝트 생성 환경설정
프로젝트 생성
- 프로젝트명 : FragmentData
- 사용언어 : Kotlin
※ Android Studio 버전 : 4.1.2
ViewBinding 설정
build.gradle(Module: ManagingFolder) 파일에 아래의 ViewBinding 설정 코드를 추가합니다.
android {
...
viewBinding {
enabled = true
}
}
코드 추가가 완료되면 아래와 같이 Sync Now 클릭해서 Gradle 변경 사항을 적용합니다.
※ ViewBinding 은 Layout 에 있는 View의 Id를 코틀린 코드에서 직접 사용 할 수 있게 해주는 도구입니다. View Binding과 관련된 설명은 아래의 링크를 참조해주세요.
Activity에서 Fragment 생성시 데이터 전달
Fragment 추가
아래 그림과 같이 FragmentA 란 이름의 Fragment를 추가합니다. Fragment 가 추가되면 아래와 같이 FragmentA.kt 파일과 fragment_a.xml 파일이 생성됩니다.
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>
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에 표시되는 것을 확인 할 수 있습니다.
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의 문자열 변경 할 예정입니다.
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가 변경 되는 것을 확인 할 수 있습니다.
끝까지 읽어 주셔서 감사합니다.
'Programming > Android App(Kotlin)' 카테고리의 다른 글
안드로이드 코틀린 : Spinner 로 목록 만들기 및 기타 설정 방법 (0) | 2021.03.30 |
---|---|
안드로이드 코틀린 : Fragment에서 Fragment 생성 및 데이터 보내기 (0) | 2021.03.30 |
안드로이드 코틀린 : Fragment 추가, 변경, 삭제 사용법 및 유의점 (1) | 2021.03.25 |
안드로이드 코틀린 : Intent 명시적 호출 방법 정리 (0) | 2021.03.25 |
안드로이드 코틀린 : 앱 디렉토리 폴더 생성, 탐색, 삭제 (0) | 2021.03.24 |