티스토리 뷰
Fragment
• 앱 UI의 재사용 가능한 부분
• 여러 개의 프래그먼트를 하나의 액티비티에 결합하여 창이 여러 개인 UI를 빌드할 수 있다.
• 하나의 fragment를 여러 액티비티에서 재사용할 수 있다.
-> 즉, 액티비티의 모듈화된 구역이라고 생각하면 편하다.
• Fragment는 자체적인 생명 주기를 갖는다.
- 생명 주기는 호스트 액티비티의 생명 주기에 직접적으로 영향을 받는다.
* 호스트 액티비티 : 해당 프래그먼트를 포함하는 액티비티
• Fragment는 자체 입력 이벤트를 수신한다.
Fragment 생명 주기
1. Activity의 onCreate(savedInstanceState)
• onAttach()
- 프래그먼트가 액티비티와 연결되어 있는 경우 호출된다.
- Activity가 전달된다.
• onCreate()
- 프래그먼트가 생성되는 시간이다.
- 초기화 작업을 한다.
• onCreateView()
- 프래그먼트가 자신의 인터페이스를 그리는 시간이다.
- View를 리턴해야 한다.
- UI가 없는 프래그먼트의 경우 null을 반환해야 한다.
• onActivityCreated()
2. Activity의 onStart()
• onStart()
3. Activity의 onResume()
• onResume()
4. Activity의 onPause()
• onPause()
- 사용자가 프래그먼트를 떠난다는 것을 나타내는 첫 번째 신호.
- 변경사항 저장 등의 작업.
5. Activity의 onStop()
• onStop()
6. Activity의 onDestroy()
• onDestroyView()
• onDestroy()
• onDetach()
- 프래그먼트가 액티비티와 연결이 끊어지는 시간이다.
Fragment 생성 방법
• 코틀린 클래스를 생성하여 Fragment() 상속
• layout을 구성할 xml 파일 생성
• 코틀린 클래스에서 onCreateView(inflater, container, savedInstanceState) 오버라이드하여 xml 파일과 연결
- inflater : xml 파일을 뷰로 만들어주는 역할
- container : 해당 프래그먼트의 부모 뷰
- savedInstanceState : 사용자의 저장된 사용 기록, 상태
- inflater.inflate(R.layout.XML파일명, container, false)을 리턴하여야 한다.
- attchToRoot : 루트 뷰에 지금 포함시킬 지(true), 나중에 포함시킬 지(false)
• FragmentOne_11.kt
package com.example.fastcampus
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
class FragmentOne_11: Fragment() { // Fragment() 상속
override fun onCreateView( // onCreateView 오버라이드
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.activity_fragment_one11, container, false) // activity_fragment_one11.xml에 해당하는 뷰를 생성
}
}
• activity_fragment_one11.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/fragmentTextView"
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#AAAAFF"
android:gravity="center"
android:text="Fragment One"
android:textSize="40dp" />
</androidx.appcompat.widget.LinearLayoutCompat>
생성한 Fragment 액티비티에 포함시키는 방법
1. xml로 포함시키기
• 프래그먼트를 포함할 호스트 액티비티 생성.
• 호스트 액티비티에서 <androidx.fragment.app.FragmentContainerView> 태그 사용하여 프래그먼트를 불러올 수 있다.
• android:id 무조건 필요
- 다른 뷰에서는 id가 필요할 때만 쓰면 됐는데 FragmentContainerView에서는 id가 필수이다.
- 이유는 아직 모르겠다.
• android:name="패키지명.프래그먼트명"
- 포함시킬 프래그먼트명을 적는다.
• 프래그먼트 뷰는 불러오는 것이기 때문에 xml 미리보기에 뜨지 않는다.
- tools:layout="@layout/XML파일명"을 통해 미리보기가 가능하다.
• activity_fragment_container11.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat 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=".FragmentContainer_11"
android:orientation="vertical" >
<TextView
android:id="@+id/hostActivityTextView"
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#000000"
android:gravity="center"
android:text="Host Activity"
android:textColor="#FFFFFF"
android:textSize="40dp" />
<androidx.fragment.app.FragmentContainerView
android:id="@+id/fragment_container_view1"
android:layout_width="match_parent"
android:layout_height="100dp"
android:name="com.example.fastcampus.FragmentOne_11"
tools:layout="@layout/activity_fragment_one11" />
</androidx.appcompat.widget.LinearLayoutCompat>
2. 코틀린 프로그래밍으로 포함시키기
• supportFragmentManager 객체의 beginTransaction() 메소드를 사용하여 FragmentTransaction 생성.
• FragmentTransaction
- 프래그먼트 연산을 위한 트랜잭션.
- 프래그먼트 추가, 삭제, 교체 등의 작업을 한다.
- FragmentTransaction.replace(부모 뷰, 프래그먼트 객체) : 존재하는 프래그먼트를 부모 뷰에 포함시킨다.
- FragmentTransaction.remove(프래그먼트 객체) : 프래그먼트를 부모 뷰에 포함시킨다.
- FragmentTransaction.commit()
- 트랜지션을 커밋한다.
- commit, commitAllowingStateLoss, commitNow, commitNowAllowingStateLoss가 있다.
- AllowingStateLoss : 저장된 상태에 대한 손실 허락 여부.
- Now : 트랜잭션을 메인 쓰레드에 예약할 것인지, 즉시 실행할 것인지 여부.
* xml로 추가한 프래그먼트는 조작하지 못한다.
* Transaction (트랜잭션)
- 쪼갤 수 없는 작업의 최소 단위
- 은행 ATM이나 데이터베이스 등의 시스템에서 사용한다.
- 여러 절차의 작업들을 하나의 트랜잭션으로 설정하면 이 작업들은 별개로 분리될 수 없고 하나의 작업으로 처리된다.
-> 따라서 트랜잭션을 이루는 여러 절차 중 몇 개는 성공하고 몇 개는 실패하고 이럴 수 없다.
-> 모든 절차가 완료되면 commit(커밋), 하나라도 오류가 발생하면 원래 상태로 rollback(롤백)한다.
ex) A가 돈을 지불하고, B가 돈을 받는 트랜잭션
-> A가 돈을 지불했지만 B가 돈을 받지 않았으면 해당 트랜잭션은 작업 실패.
-> A의 돈 지불, B의 돈 받기가 모두 성공하여야 하나의 트랜잭션이 완료된 것.
• activity_fragment_container11.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat 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=".FragmentContainer_11"
android:orientation="vertical" >
<TextView
android:id="@+id/hostActivityTextView"
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#000000"
android:gravity="center"
android:text="Host Activity"
android:textColor="#FFFFFF"
android:textSize="40dp" />
<androidx.fragment.app.FragmentContainerView
android:id="@+id/fragment_container_view1"
android:layout_width="match_parent"
android:layout_height="100dp"
android:name="com.example.fastcampus.FragmentOne_11"
tools:layout="@layout/activity_fragment_one11" />
<TextView
android:id="@+id/textAdd"
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#FFAAAA"
android:gravity="center"
android:text="add"
android:textSize="40dp" />
<TextView
android:id="@+id/textRemove"
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#FFAAAA"
android:gravity="center"
android:text="remove"
android:textSize="40dp" />
<LinearLayout
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="100dp"
android:orientation="horizontal"/>
</androidx.appcompat.widget.LinearLayoutCompat>
• FragmentContainer_11.kt
package com.example.fastcampus
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.TextView
class FragmentContainer_11 : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_fragment_container11)
val fragmentManager = supportFragmentManager // supportFragmentManager 객체 생성
val fragmentOne = FragmentOne_11()
findViewById<TextView>(R.id.textAdd).setOnClickListener {
val transaction = fragmentManager.beginTransaction() // beginTransaction() 메소드로 FragmentTransaction 객체 생성
transaction.replace(R.id.root, fragmentOne) // root 뷰에 fragmentOne 포함
transaction.commit() // 트랜지션 커밋
}
findViewById<TextView>(R.id.textRemove).setOnClickListener {
val transaction = fragmentManager.beginTransaction() // beginTransaction() 메소드로 FragmentTransaction 객체 생성
transaction.remove(fragmentOne) // fragmentOne 삭제
transaction.commit() // 트랜지션 커밋
}
}
}
Fragment와 Activity 상호 접근
1. 호스트 Activity에서 Fragment로 데이터 전달하기
• 프래그먼트는 호스트 액티비티에 포함되어 있기 때문에, 호스트 액티비티에서 프래그먼트로 쉽게 접근이 가능하다.
• 호스트 액티비티에서는 프래그먼트 객체의 arguments 프로퍼티에 접근하여 bundle 타입의 데이터를 보내고, 프래그먼트에서는 arguments 프로퍼티에 전달된 데이터를 getString 등의 메소드로 받아 데이터를 사용할 수 있다.
• FragmentContainer_11.kt
package com.example.fastcampus
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.TextView
class FragmentContainer_11 : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_fragment_container11)
val fragmentManager = supportFragmentManager
val fragmentOne = FragmentOne_11()
findViewById<TextView>(R.id.textAdd).setOnClickListener {
val transaction = fragmentManager.beginTransaction()
val bundle = Bundle() // Bundle 객체 생성
bundle.putString("key", "hello") // string 데이터 넣음
fragmentOne.arguments = bundle // 프래그먼트의 arguments 프로퍼티에 접근하여 전달
transaction.replace(R.id.root, fragmentOne)
transaction.commit()
}
findViewById<TextView>(R.id.textRemove).setOnClickListener {
val transaction = fragmentManager.beginTransaction()
transaction.remove(fragmentOne)
transaction.commit()
}
}
}
• FragmentOne_11.kt
package com.example.fastcampus
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
class FragmentOne_11: Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.activity_fragment_one11, container, false)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val data: String? = arguments?.getString("key") // arguments 프로피터로 전달받은 데이터 data 변수에 저장
Log.d("testt", "data : " + data) // Logcat에 출력
}
}
• 결과
- 첫 번째로 나온 null은 xml로 포함한 프래그먼트의 로그이다.
-> xml로 포함한 프래그먼트에는 데이터 전달이 어렵다고 한다.
- add를 눌러 포함된 두 번째 프래그먼트에서는 전달된 문자열 데이터 hello가 정상적으로 출력되었다.
- 프래그먼트를 포함하고 삭제하고를 반복할 때 마다 잘 출력이 된다.
2. Fragment에서 호스트 Activity로 접근하기
• 호스트 액티비티에 있는 함수를 Fragment에서 접근해보자.
• 호스트 액티비티인 FragmentContainer_11.kt에 printTestLog 함수 생성
package com.example.fastcampus
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.TextView
class FragmentContainer_11 : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_fragment_container11)
val fragmentManager = supportFragmentManager
val fragmentOne = FragmentOne_11()
findViewById<TextView>(R.id.textAdd).setOnClickListener {
val transaction = fragmentManager.beginTransaction()
val bundle = Bundle()
bundle.putString("key", "hello")
fragmentOne.arguments = bundle
transaction.replace(R.id.root, fragmentOne)
transaction.commit()
}
findViewById<TextView>(R.id.textRemove).setOnClickListener {
val transaction = fragmentManager.beginTransaction()
transaction.remove(fragmentOne)
transaction.commit()
}
}
fun printTestLog() { // printTestLog 함수 생성
Log.d("testt", "print test log")
}
}
• 프래그먼트인 FragmentOne_11.kt에서 호스트 액티비티의 printTestLog 함수 접근
- activity 키워드로 호스트 액티비티를 가져올 수 있다.
- 프래그먼트는 여러 액티비티에서 재사용되어 사용될 수 있기 때문에, 호스트 액티비티가 여러 개 있을 수 있다.
-> 원하는 호스트 액티비티로 캐스팅 해주어야 한다.
package com.example.fastcampus
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.fragment.app.Fragment
class FragmentOne_11: Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val fragmentView = inflater.inflate(R.layout.activity_fragment_one11, container, false) // inflater로 만든 뷰를 바로 리턴하지 않고 변수에 저장
fragmentView.findViewById<TextView>(R.id.fragmentTextView).setOnClickListener { // 뷰에 클릭 리스너 추가
(activity as FragmentContainer_11).printTestLog() // activity 키워드로 호스트 액티비티 가져오기. 호스트 액티비티 중 FragmentContainer_11로 캐스팅
}
return fragmentView // 뷰 리턴
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val data: String? = arguments?.getString("key")
Log.d("testt", "data : " + data)
}
}
3. 호스트 Activity에서 Fragment로 접근하기
• 프래그먼트에 있는 함수를 호스트 액티비티에서 접근해보자.
• 프래그먼트인 FragmentOne_11.kt에 printTestLogFragment() 생성.
package com.example.fastcampus
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.fragment.app.Fragment
class FragmentOne_11: Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val fragmentView = inflater.inflate(R.layout.activity_fragment_one11, container, false)
fragmentView.findViewById<TextView>(R.id.fragmentTextView).setOnClickListener {
(activity as FragmentContainer_11).printTestLog()
}
return fragmentView
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val data: String? = arguments?.getString("key")
Log.d("testt", "data : " + data)
}
fun printTestLogFragment() {
Log.d("testt", "print test log by fragment")
}
}
• 호스트 액티비티인 FragmentContainer_11.kt에서 프래그먼트의 printTestLogFragment 함수 접근
package com.example.fastcampus
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.TextView
class FragmentContainer_11 : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_fragment_container11)
val fragmentManager = supportFragmentManager
val fragmentOne = FragmentOne_11()
findViewById<TextView>(R.id.textAdd).setOnClickListener {
val transaction = fragmentManager.beginTransaction()
val bundle = Bundle()
bundle.putString("key", "hello")
fragmentOne.arguments = bundle
transaction.replace(R.id.root, fragmentOne, "fragmentOneTag") // 접근을 위한 Tag 입력
transaction.commit()
}
findViewById<TextView>(R.id.textRemove).setOnClickListener {
val transaction = fragmentManager.beginTransaction()
transaction.remove(fragmentOne)
transaction.commit()
}
findViewById<TextView>(R.id.hostActivityTextView).setOnClickListener {
// xml로 포함시킨 fragment를 id로 접근
val fragmentOne = supportFragmentManager.findFragmentById(R.id.fragment_container_view1) as FragmentOne_11
fragmentOne.printTestLogFragment()
// 코틀린 프로그래밍으로 포함시킨 fragment를 tag로 접근
val fragmentOne2 = supportFragmentManager.findFragmentByTag("fragmentOneTag") as FragmentOne_11
fragmentOne2.printTestLogFragment()
}
}
fun printTestLog() {
Log.d("testt", "print test log")
}
}
• 결과
- xml로 포함시킨 프래그먼트에서 나온 로그와 코틀린 프로그래밍으로 포함시킨 프래그먼트에서 나온 로그 모두 잘 출력된 모습.
* 코틀린 프로그래밍으로 포함시킨 프래그먼트의 로그를 띄우기 위해선 add를 눌러 프래그먼트를 추가해줘야 한다.
이 글은
패스트 캠퍼스 Android 앱 개발의 정석 with Kotlin 올인원 패키지 Online
강의를 듣고 공부한 내용을 바탕으로 작성되었습니다.
'📱 Android > 💡 개념' 카테고리의 다른 글
[Android/개념] 13. 동기(Synchronous) & 비동기(Asynchronous) (0) | 2022.11.04 |
---|---|
[Android/개념] 12. Thread(쓰레드) (0) | 2022.11.04 |
[Android/개념] 10. Bundle(번들) (0) | 2022.11.03 |
[Android/개념] 9. Text Changed Listener (0) | 2022.11.02 |
[Android/개념] 8. Activity Stack(액티비티 스택) (0) | 2022.11.01 |