Fragment와 Activity의 관계
Fragment의 뜻은 사전적 정의로 '조각'이라는 뜻이다.
그 뜻에 걸맞게 fragment는 activity를 이루는 조각이다. 우리는 모든 화면을 activity로 만들고 Intent로 통신할 수 있다. 그러나 그렇게 한다면, 자원을 불필요하게 많이 사용할 수 있다. 그 이유는 acivity는 stack형식으로 데이터가 쌓이기 때문이다. fragment를 사용한다면 하나의 activity 위에서 여러 개의 화면을 사용할 수 있다. 즉, 화면을 분할시킬 수 있다는 의미이다. 이런 식으로 앱을 만든다면 보다 효율적으로 자원을 사용할 수 있다.
Fragment에서 Activity로 값 전달하기
내가 하고 싶었던 것은 아주 간단하다. DialogFragment에 버튼을 생성하고 이것을 누르면, camera를 작동시키는 intent를 실행시키는 것이었다. 이 intent는 activity에 구현되어 있었기 때문에 fragment 안에 있는 button의 onClickListener와 activity 안에 있는 camera intent에 신호를 줄 수 있어야 한다. 이것의 해결책을 아주 간단한 예시로 보여주도록 하겠다.
예시
이 예시는 activity 안에 있는 startButton을 눌렀을 때 DialogFragment가 실행되고, 이 dialog 안에 있는 버튼을 눌렀을 때 activity의 textview에 변화를 주면서 fragment를 닫는 것을 구현하였다.
# 결과
위의 코드를 실행시키면 다음과 같은 결과를 얻을 수 있다.
왼쪽이 가장 처음 화면이다. 이 화면에서 Start 버튼을 클릭하였을 때, DialogFragment가 실행된다. 만약 이 버튼을 누른다면 오른쪽 화면과 같이 TextView의 Text가 "hello"에서 "FragmentClicked"로 바뀌는 것을 확인할 수 있다.
# CallBack.kt
package com.example.fragment_to_activity_example
interface CallBack {
fun callBackExample()
}
먼저 이번 글쓰기의 핵심이다.
CallBack interface를 작성해 주었다. CallBack을 interface로 선언한 이유는 Fragment의 버튼을 눌렀을 때, MainActivity에 있는 TextView에서 변화가 일어나야 하기 때문이다. 만약 CallBack을 Class로 작성하였다면, MainActivity에 있는 TextView에 접근하지 못해 에러가 발생할 것이다. CallBack을 interface로 선언하고 MainActivity.kt에 implement 하여 MainActivity에 있는 TextView에 접근할 수 있도록 하였다. 먼저 CallBack의 메서드인 CallBackExample을 Override 하여 TextView를 변화시킬 수 있도록 프로그래밍하였다.
만약 값을 전송하고 싶다면, callBackExample 메서드의 매개변수 부분에 값을 넣으면 된다.
# MainActivity.kt
package com.example.fragment_to_activity_example
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
class MainActivity : AppCompatActivity(), CallBack {
lateinit var exampleText:TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val startButton = findViewById<Button>(R.id.button_start)
exampleText = findViewById(R.id.textView_example)
startButton.setOnClickListener {
ExampleFragment(this).show(supportFragmentManager, "ExampleFragment")
}
}
override fun callBackExample() {
exampleText.setText("Fragment Clicked")
}
}
위의 코드에서 override fun callBackExample()이라는 구문이 보일 것이다. 이 메서드를 override 하여 내부 코드를 작성하고, 이것을 아래 ExampleFragment.kt의 생성자에 넘겨준다. 그리고 이 메서드를 ExampleFragment에 있는 버튼이 눌렸을 때 실행시키도록 프로그래밍한다면 CallBack이 가능하다. 즉, setText가 동작하면서 MainActivity의 상태가 변한다.
# ExampleFragment.kt
package com.example.fragment_to_activity_example
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import androidx.fragment.app.DialogFragment
class ExampleFragment(_callBack:CallBack) : DialogFragment() {
val callBack:CallBack
init {
callBack=_callBack
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val exampleInflater = inflater.inflate(R.layout.fragment_example, container, false)
exampleInflater.findViewById<Button>(R.id.btn_example).setOnClickListener {
callBack.callBackExample()
dismiss()
}
return exampleInflater
}
}
다음과 같이 코드를 작성하였다. ExampleFragment에 있는 버튼을 클릭할 때, callBackExample() 메서드가 실행되며, dismiss()를 하여 MainActivity의 변화와 함께 해당 fragment는 종료하도록 프로그래밍하였다.
# activity_main.xml
# fragment_example.xml
다음과 같이 xml 코드를 작성하였다. fragment의 Activitiy 및 xml부분은 File> New> Fragment> Fragment(black)를 통해 빈 fragment을 생성한 다음 수정한 것이다.
아래에 github의 repository를 남기겠다. 코드를 하나하나 작성하고 싶지 않거나, 똑같이 구현하고 싶다면 참고하도록 하자.