안녕하세요, 반갑습니다!
현존하는 안드로이드 앱 중에서 프래그먼트를 안쓰는 앱이 있을까요?
아마 대부분 프래그먼트를 사용하는 앱일 것입니다.
주로 뷰페이저 또는 탭 레이아웃에 많이 쓰이죠
프래그먼트(Fragment) 는 하나의 액티비티에 각 화면을 분할, 독립적인 코드로 구성하는 것을 말합니다.
그래서 액티비티와 프래그먼트,
프래그먼트와 또 다른 프래그먼트끼리 통신을 할 필요가 있습니다.
어떻게 할 수 있을까요?
바로 시작합니다!
액티비티 < - > 프래그먼트
A프래그먼트 < - > 액티비티 < - > B프래그먼트
데이터 전달하기
1. 프래그먼트 띄우기
데이터를 전달하기 위해서 간단한 앱을 만들겠습니다.
이미 구성하신 분들은 2번부터 봐주세요~
아래와 같이 프래그먼트 클래스 및 .xml 를 먼저 만들어주세요.
그리고 각각의 레이아웃을 만들어 주시는데요.
저는 간단히 영화 포스터를 보여주고 버튼을 누르면 상세화면으로 바뀌도록 구성했습니다.
fragment_a.xml
fragment_b.xml
그래서 우선 액티비티에서 A_Fragment() 를 즉시 띄우도록 했습니다.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
.
.
.
setFragment(A_Fragment())
}
//프래그먼트 띄우기
fun setFragment(fragment: Fragment) {
val transaction = supportFragmentManager.beginTransaction()
transaction.replace(R.id.frameLayout, fragment)
transaction.commit()
}
}
2. 액티비티에서 프래그먼트로 데이터 전달하기
자, 저는 액티비티에서 곧바로 A_Fragment() 를 띄우도록 했는데요.
데이터도 같이 보내도록 하겠습니다.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
.
.
.
//setFragment(A_Fragment())
setDataAtFragment(A_Fragment(), "버킷 리스트")
}
//프래그먼트에 데이터 전달하기
fun setDataAtFragment(fragment:Fragment, title:String) {
val bundle = Bundle()
bundle.putString("title", title)
fragment.arguments = bundle
setFragment(fragment)
}
//프래그먼트 띄우기
fun setFragment(fragment: Fragment) {
val transaction = supportFragmentManager.beginTransaction()
transaction.replace(R.id.frameLayout, fragment)
transaction.commit()
}
}
기존의 코드에서 setDataAtFragmetn() 함수를 추가해줬습니다.
데이터를 Fragment 의 arguments 에 넣어주는 함수죠.
(안드로이드는 프래그먼트 생성과 동시에 데이터를 전달하거나 받을 수 있는 arguments 를 제공합니다.)
이 argument 는 Bundle객체로 데이터를 전달할 수 있고,
Bundle 객체는 데이터를 Key와 Value 의 쌍으로 전달합니다.
액티비티에서 데이터를 전달했고, 프래그먼트는 받아야 겠죠?
아래 코드로 받을 수 있습니다.
class A_Fragment : Fragment() {
private var title: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
title = it.getString("title")
}
Log.d("A_Fragment", "영화 제목 : ${title}")
}
}
이렇게 로그로 확인할 수 있습니다.
간단하죠?
이렇게 액티비티에서 프래그먼트로 데이터를 전달했습니다.
그럼 이제 반대로 프래그먼트에서는 액티비티로 어떻게 전달하는 방법을 알아보겠습니다.
3. 프래그먼트에서 액티비티로 데이터 전달하기
액티비티에서는 프래그먼트의 arguments 를 이용해 데이터를 전달했습니다.
그런데 프래그먼트에서 액티비티로 전달하는 것은 더 쉽고 간단합니다.
class A_Fragment : Fragment() {
.
.
.
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
.
.
.
//'상세보기' 버튼을 눌렀을 때
btnGoDetail.setOnClickListener {
val mActivity = activity as MainActivity
mActivity.receiveData("A프래그먼트")
}
}
}
끝났습니다.
너무 간단하죠?
그저 액티비티 객체를 만들어 액티비티에 만들어 둔 함수를 호출해주면 됩니다.
물론 호출 하기 전에 액티비티에는 receiveData() 라는 함수를 만들어놔야 합니다.
class Main() {
fun onCreate() {
.
.
.
}
fun receiveData(who:String) {
Log.d("Main", "누구인가요? '${who}'입니다")
}
}
역시 '상세보기' 버튼을 누름과 동시에 로그를 확인할 수 있습니다.
4. 프래그먼트에서 프래그먼트로 데이터 전달하기
2, 3번의 방법으로 액티비티와 프래그먼트 간 데이터를 전달했습니다.
그럼 프래그먼트와 프래그먼트끼리 데이터는 어떻게 전달할 수 있을까요?
네, 맞습니다.
결국은 액티비티가 프래그먼트를 교체하는 것이기 때문에 위 방법을 그대로 사용하면 됩니다.
그래도 한번 보겠습니다.
크게 다르지 않습니다.
먼저, A_Fragment()의 '상세보기' 버튼을 눌러 MainActivity 의 setDataAtFragmetn() 를 호출, 교체할 프래그먼트와 데이터를 파라미터로 전달합니다.
class A_Fragment : Fragment() {
.
.
.
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
.
.
.
//'상세보기' 버튼을 눌렀을 때
btnGoDetail.setOnClickListener {
val mActivity = activity as MainActivity
mActivity.setDataAtFragment(B_Fragment(), "버킷리스트")
}
}
}
MainActivity 에서는 딱히 건드릴게 없네요.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
.
.
.
setDataAtFragment(A_Fragment(), "버킷 리스트")
}
//A_Fragment 에서 데이터를 수신
fun setDataAtFragment(fragment:Fragment, title:String) {
val bundle = Bundle()
bundle.putString("title", title)
fragment.arguments = bundle
setFragment(fragment)
}
//데이터가 셋팅된 프래그먼트 띄우기
fun setFragment(fragment: Fragment) {
val transaction = supportFragmentManager.beginTransaction()
transaction.replace(R.id.frameLayout, fragment)
transaction.commit()
}
}
마지막으로 최종 목적지인 B_Fragment 의 onCreate() 에서 값을 가져올 수 있습니다.
class B_Fragment : Fragment() {
private var title: String? = null //전역변수로 사용
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
title = it.getString("title") //데이터 수신
}
}
}
감사합니다.