안드로이드와 앱/안드로이드

프래그먼트 Fragment

정혜현 2024. 7. 29. 09:29

정의 

안드로이드 애플리케이션의 UI 부분을 모듈화한 사용자 인터페이스

 

 

 

특징 

독립불가 : 액티비티 위에서 동작하므로 액티비티와 분리되어 동작할 수 없다.

 

재사용성 : 하나의 액티비티에 여러 개의 프래그먼트를 조합하여 창이 여러 개인 UI를 구축할 수 있고, 하나의 프래그먼트를 여러 액티비티에서 재사용할 수 있다.

 

빠르고 효율적 : 액티비티로 화면을 넘기는 것보다 프래그먼트로 일부만 바꾸는 것이 자원 이용량이 적어 속도가 빠르다.

 

ᖜ ‿ᖜ 그렇다면 액티비티는 프래그먼트를 붙여놓기 위한 그저 배경인가?

탭레이아웃같은 전역 요소는 액티비티에 배치해야 한다.

목적에 따라 액티비티와 프래그먼트 중 적합한 곳에 배치하며 적절히 사용할 것.

 

ViewPager2
화면을 스와이프하면 탭과 함께 움직이는 뷰. 액티비티안에 n개의 프래그먼트가 선언되어 있는 구조

 

 

데이터 전달

액티비티 → 프래그먼트, 프래그먼트 → 프래그먼트

인스턴스를 생성하고 newInstance 메소드를 통해 데이터를 전달

Bundle 객체를 사용하여 데이터를 프래그먼트의 인자arguments로 설정

ᖜ ‿ᖜ Bundle?

Map형태로 구성된 Data묶음

키 : String 값 : Int, String, Serializable, Parcelable ..

 

프래그먼트 → 액티비티 

FragmentDataListener 인터페이스를 정의하고, 프래그먼트가 액티비티에 붙을 때 onAttach 액티비티가 이 인터페이스를 구현했는지 확인. 버튼 클릭 리스너에서 onDataReceived 메소드를 호출하여 데이터를 액티비티에 전달

 

 

 

 

FragmentManager

프래그먼트 매니저

프래그먼트의 추가, 삭제, 교체 등 작업을 관리하는 클래스

커밋하는 각 프래그먼트 변경사항 집합을 트랜잭션Transaction 이라고 한다.

트랜잭션을 관리하는 역할이다.

 

 

 

 

Transaction

트랜잭션

프래그먼트 변경사항 집합

FragmentTransaction 클래스에 의해 제공되는 API로 트랜잭션 내 실행할 작업을 지정할 수 있다. 

프래그먼트 추가 add(), 삭제 remove(), 교체 replace(), 분리 detach() 메소드로 를 지정할 수 있다.

트랜잭션의 마지막은 commit()을 호출해야하며 매니저에게 작업이 트랜잭션에 추가되었음을 알려주는 역할이다.

 

addToBackStack()으로 매니저 백스택에 트랜잭션을 저장할 수 있다.  

커밋을 호출하더라도 트랜잭션이 즉시 실행되지 않고 가능한 빨리 기본 UI 스레드에서 실행되도록 예약된다. 필요한 경우 commitNow()로 즉시 실행할 수 있다. 단, commitNow()와 addToBackStack()은 호환되지 않는다.

executePendingTransactions()은 아직 실행되지 않은 것을 실행해주고 addToBackStack()과도 호환된다.

 

 

 

 

BackStack

백스택

현재 프래그먼트의 작업(추가 삭제 등의 트랜잭션)을 취소하고 백스택에 커밋된 트랜잭션을 불러와서 이전 프래그먼트를 다시 가져올 수 있다. 매니저의 메소드로 여러 백스택을 지원할 수 있고 대표적인 예로 하단 탭이 있다. 하나의 백스택을 저장하고 다른 스택을 복원하여 여러 백스택 간 전환이 가능하다. 백스택 지원을 자동으로 처리하는 NavigationUI 구성요소를 사용할 수도 있다.

ᖜ ‿ᖜ 불러오기, 백업같은 느낌

 

예시

1. addToBackStack()으로 추가 : 이 프래그먼트를 저장할거야

프래그먼트를 커밋해서 트랜잭션과 상태를 백스택에 추가하는데 여기서 지정한 매개변수를 동일하게 사용해야 한다.
addToBackStack()을 호출하지 않으면 소멸되므로 사용자가 이를 다시 탐색할 수 없다. 프래그먼트를 삭제할 때 addToBackStack()을 호출하면 프래그먼트는 STOPPED 상태일 뿐이고 나중에 사용자가 뒤로 탐색할 때 RESUMED 상태가 된다.

supportFragmentManager.commit {
  replace<Fragment>(R.id.fragment_container)
  setReorderingAllowed(true)
  addToBackStack("replacement")
}

 

 

2. saveBackStack()으로 저장 : 이 프래그먼트의 작업과 상태를 저장해줘
지정된 트랜잭션과 백스택에서 이 트랜잭션 이후에 있는 모든 트랜잭션이 표시된다.

 

ᖜ ‿ᖜ popBackStack()과 saveBackStack()의 차이

popBackStack()은 최상위 프래그먼트 트랜잭션이 스택에서 사라지며 특정 트랜잭션으로 다시 돌아가지만

saveBackStack()은 표시된 트랜잭션에 있는 모든 프래그먼트의 트랜잭션을 저장한다.

즉 복원은 비슷하게 작동하나 popBackStack()은 불러오면 되돌릴 수 없고 saveBackStack()은 불러와도 이전으로 돌아갈 수 있다.

supportFragmentManager.saveBackStack("replacement")

 

 

3. restoreBackStack()로 복원
모든 표시된 트랜잭션과 상태를 복원할 수 있다.

supportFragmentManager.restoreBackStack("replacement")

 

 

하나의 매니저만 백스택을 제어할 수 있다. 

 

 

 

 

 

Fragment 생성

FragmentActivity 내에 프래그먼트를 삽입해야 한다. FragmentActivity는 AppCompatActivity의 기본 클래스이다.

레이아웃 생성

  • 정적추가(XML 접근 방식) : 액티비티 레이아웃의 name 속성에 프래그먼트 클래스 이름을 지정하면 지정된 프래그먼트가 자동으로 인스턴스화 되어 액티비티 레이아웃이 확장된다. 정확히는 인스턴스화된 프래그먼트에 onInflate()가 호출되며 트랜잭션을 커밋한다.

 

  • 동적추가(프로그래매틱 방식) : onCreate에서 replace()의 인자로 레이아웃 id와 fragment 클래스를 전달해 인스턴스화한 다음 트랜잭션을 커밋한다.  

ᖜ ‿ᖜ 어떻게 인스턴스화할까?

replace()메소드 인자로 프래그먼트를 넣으면 매니저가

프레임워크에서 제공하는 FragmentFactory를 사용해 해당 프래그먼트를 인스턴스화한다.

 

 

supportFragmentManager.commit {
            replace(R.id.frameLayout, frag)//레이아웃 id, 프래그먼트
            setReorderingAllowed(true)
            addToBackStack("")
        }

 

supportFragmentManager.commit {} : 매니저에게 스코프 내 트랜잭션을 커밋하는 코드

replace(R.id.frameLayout, frag) : 프래그먼트를 인스턴스화하는 코드

setReorderingAllowed(true) : 애니메이션과 전환이 올바르게 작동하도록 트랜잭션과 관련된 프래그먼트의 상태 변경을 최적화하는 코드. 이를 통해 여러 트랜잭션이 함께 실행돼도 중간 프래그먼트의 생명 주기가 변경되지 않거나 애니메이션 또는 전환이 실행되지 않는다. 

addToBackStack() : 트랜잭션을 백스택에 커밋하는 코드

 

 

 

 

 

생명주기

자체적인 생명주기lifecycle를 가지며 액티비티의 생명주기와 밀접 (액티비티 안에 있으므로 영향을 받기 때문)
생명주기에 맞춰 적절한 작업을 수행해야 메모리 누수를 방지하고 애플리케이션의 성능을 최적화할 수 있다.

 

onAttach()
프래그먼트가 액티비티에 연결될 때 호출
이 시점에서 프래그먼트는 액티비티와 아직 완전히 연결되지는 않았다.
onCreate()
프래그먼트가 생성될 때 호출
초기화 작업, 리소스 바인딩 등을 수행
onCreateView()
프래그먼트의 레이아웃을 인플레이트하는 곳
뷰를 생성하고, 레이아웃을 설정
onActivityCreated()
액티비티의 onCreate() 메서드가 완료된 후 호출
액티비티와 프래그먼트의 뷰가 모두 생성된 상태. 뷰와 관련된 초기화를 수행
onStart()
프래그먼트가 사용자에게 보여질 준비가 되었을 때 호출
필요한 리소스 할당, 애니메이션 시작
onResume()
프래그먼트가 사용자와 상호작용할 수 있는 상태가 되었을 때 호출
프래그먼트가 포그라운드에 있을 때 실행되는 작업을 여기서 처리
onPause()
프래그먼트가 일시정지될 때 호출
상태 저장, 스레드 중지 등의 작업을 수행
onStop()
프래그먼트가 더 이상 사용자에게 보이지 않을 때 호출
리소스 해제, 스레드 정지 등을 수행
onDestroyView()
프래그먼트의 뷰와 관련된 리소스를 정리할 때 호출
onDestroy()
프래그먼트가 파괴될 때 호출
프래그먼트의 상태를 정리하고, 모든 리소스를 해제
onDetach()
프래그먼트가 액티비티로부터 분리될 때 호출
프래그먼트가 액티비티와의 모든 연결을 해제

 


 


 

ᖜ ‿ᖜ

 

프래그먼트를 배울 당시, 주입되는 지식의 양질은 기하급수적으로 늘어나서 익히고 정리하며 흡수시킬 시간이 부족했다. 데이터 전달을 제대로 숙지하지 못한 채 프로젝트가 시작됐고 앱을 만들면서 이론이 빈 상태로 실전에 적용하려니 껍데기만 모방했을 뿐, 작동원리를 이해하지 못한 나는 버그가 나타나도 쉽게 해결하지 못했다.

 

강의를 복습하면서 데이터 전달 코드를 하나하나 분석해보고 싶어졌고 매니저와 트랜잭션을 찾아보니 프래그먼트가 작업을 어떻게 저장하고 관리하는지 파악할 수 있었다. 생각보다 더 깊이있는 내용들이 많아 추후 수정하며 프래그먼트의 이해를 확장시킬 예정.

 

 

 

 

 

이하 정리중...

액티비티 또는 프래그먼트에서 접근할 수 있다.

getSupportFragmentManager() 액티비티에서 프래그먼트 매니저에 접근할 수 있게 해주는 메소드

 

 

프래그먼트는 하나 이상의 하위 프래그먼트를 호스팅할 수 있습니다. 프래그먼트 내에서 getChildFragmentManager()를 통해 프래그먼트의 하위 요소를 관리하는 FragmentManager 참조를 가져올 수 있습니다. 호스트 FragmentManager에 액세스해야 한다면 getParentFragmentManager()를 사용하면 됩니다.

 

 

 

 

콜백 메서드란 다른 함수에 인수로 전달되는 함수이며, 일종의 이벤트 후에 실행될 것으로 예상된다. 콜백 메서드의 목적은 다른 클래스에서 일부 작업이 완료된 경우 클래스 Sync/Async에 알리는 것이다. 이는 비동기 작업을 할 때 매우 유용하다. 버튼을 누르거나 인터넷에서 데이터를 가져온 후 일부 작업을 수행하거나, 컨텐츠를 표시하는 등의 일상적인 작업을 수행하려 한다고 가정한다. 콜백 기능을 통해 버튼을 누르면 알림을 받으므로 이벤트 처리에 사용된다. 이 유형의 디자인 패턴은 관찰자 디자인 패턴(Observer design pattern)에 사용된다.

 

 

 

일반적인 함수 호출(call)은 호출하는 함수, 호출자와 호출되는 함수, 피호출자로 나눠져서 호출자가 피호출자를 불러 함수의 기능을 수행한다고 한다.
반면 콜백(callback)은 호출(call)을 거꾸로(back) 하는 것이라고 한다. 피호출자가 호출자를 부르는 것이다.

즉, 일반적으로 사용자가 시스템에 임의의 서비스를 호출하는 것이 보편적이다. 처리 루틴은 시스템에 있고 사용자가 해당 루틴을 요청함에 따라 동작이 일어나는 것이다.
이 호출과는 달리 시스템 측에서 이벤트를 발생시켜 이 처리를 해달라고 요청해오는 과정에서 콜백이 사용된다. 일반적인 경우와는 반대인 상황이다.

이러한 콜백의 장점은 특정 조건이 만족됐을 때 지정한 기능을 수행하는 경우, 조건을 확인하기 위해 계속해서 조건을 만족하는지 확인하는 과정 없이 조건이 만족됐을 때 기능을 호출하기 때문에 효율적으로 기능을 수행할 수 있다는 것이다.
비동기로 조건에 대한 작업을 수행할 수 있게 되기 때문이다.

 

리스너 : 특정 이벤트를 처리하는 인터페이스, 이벤트 발생 여부를 기다리다가 이벤트 발생시 해당 이벤트에 맞는 처리를 수행하는 객체ㅍ이벤트 리스너란 뷰 클래스 안에 있는 일종의 인터페이스로, 이 안에 하나의 콜백 메서드가 들어 있다.
이 메서드는 리스너가 등록된 뷰가 UI 안의 항목과 사용자의 상호작용으로 인해 트리거됐을 때 안드로이드 프레임워크가 호출된다.
이벤트 리스너 인터페이스 안에 포함된 콜백 메서드는 onClick(), onLongClick(), onFocusChange() 등이다.

 

 

 

메소드 확인

https://medium.com/depayse/android-fragment-2-fragment-%EB%B3%B4%EC%97%AC%EC%A3%BC%EA%B8%B0%EC%99%80-%EC%B6%94%EA%B0%80-%EC%82%AD%EC%A0%9C-2f7eed396e07