Android/note

[Android] SupportFragmentManager 파도타기

김 안개 2023. 6. 18. 11:57

Fragment의 BackStack 과정에 대해 알아보다가 supportFragmentManager는 어떤 과정으로 사용이되는거지...?

싶어서 알아본 supportFragmentManager

 

일단 Fragment를 사용하다보면

supportFragmentManager.beginTransaction()

위와 같은 코드를 굉장히 많이 사용했는데 어떻게 FragmentManager가 동작하는지 알고싶었음..

 

[0] SupportFragmentManager

 

Activity와 관련있는 (Activity 위에서 사용 될) Fragment를 위해 상호작용을 목적으로 하는 FragmentManager를 생성한 후 조작을 가능케하는 역할을 함!

 

[1] supportFragmentManager

 

/* FragmentActivity.java */

@NonNull
public FragmentManager getSupportFragmentManager() {
	return mFragments.getSupportFragmentManager()
}

 

mFragments에서 getSupportFragmentManager()를 통해 FragmentManager를 반환하는데

mFragments가 뭘까?

 

[2] mFragments

 

/* FragmentActivity.java */

final FragmentController mFragments = FragmentController.createController(new HostCallbacks());

mFragments는 FragmentController 타입의 변수이며, createController를 통해 FragmentController가 생성되는구나~

근데 final 로 선언되어있으니 지금 FragmentController를 생성하면 끝이구나! 사용만 가능하겠구나!

 

근데 FragmentController는 뭔데?

 

[3] FragmentController

 

Provides integration points with a FragmentManager for a fragment host

It is the responsibility of the host to take care of the Fragment's lifecycle. The mothods provided by FragmentController are for that purpose.

fragment host (fragment와 연결되어 있는 activity)를 위해 FragmentManager와 함께 integration points를 제공한다

Fragment의 lifecycle을 take care 하기 위해 host (연결된 activity)의 책임 -> 이 책임을 위해 FragmentController에서 제공!

 

한 마디로 Activity와 연결되어 있는 Fragment의 Lifecycle을 책임지고 관리하기 위한 메소드라고 이해했다

 

[4] FragmentController.createController(new HostCallback())

 

mFragments = FragmentController.createController(new HostCallback())

어떻게 createController가 생성되는지 메소드를 확인해보면

/* FragmentController.java */

@NonNull
public static FragmentController createController(@NonNull FragmentHostCallback<?> callbacks) {
	return new FragmentController(checkNotNuull(callbacks, "callbacks == null")
}

createController 내의 FragmentController의 생성자를 통해 FragmentController의 객체가 생성된다.

생성자를 알아보기 전에 파라미터로 FragmentHostCallback을 주는것을 알 수 있다.

 

위에서 new HostCallback()으로 FragmentHostCallback의 객체를 생성해서 전달해주는데...

이건 뭐냐능

 

[5] new HostCallback()

 

/* FragmentActivity.java */

public HostCallbacks() {
	super(FragmentActivity.this) /* fragmentActivity */
}

어어 근데 super로 부모 클래스로 넘겨주네... 어어.. 계속 알아봐보자

/* FragmentHostCallback.java */

@SuppressWarnings("deprecation")
FragmentHostCallback(@NonNull FragmentActivity activity) {
	this(activity, activity /* context */, new Handler(), 0 /* windowAnimations */)
}

근데 어노테이션에서도 볼 수 있듯 deprecation되어서 this를 통해 다른 생성자로 매개변수를 넘겨준다!

/* FragmentHostCallback.java */

FragmentHostCallback(@Nullable Activity activity, @NonNull Context context, @NonNull Handler handler, int windowAnimations) {
	mActivity = activity;
    mContext = Preconditions.checkNotNull(context, "context == null");
    mHandler = Preconditions.checkNotNull(handler, "handler == null");
    mWindowAnimations = windowAnimations;
}

 

-> 여기서 한가지 궁금했던 점은 FragmentActivity.java의 클래스 안에서 HostCallBack의 메소드를 사용하는데 super를 통해 FragmentHostCallback.java로 넘어왔다는 것

super는 부모 클래스의 생성자를 사용하는 것인데, FragmentActivity는 ComponentActivity를 확장하고 있지만 FragmentHostCallback을 확장하고 있지는 않다.

 

그런데 어떻게 super를 사용할 수 있는 것이지?

코드를 조금 살펴보았더니 FragmentActivity의 클래스 내에 HostCallbacks 클래스를 생성하였고, HostCallbacks 클래스는 FragmentHostCallback<FragmentActivity> 클래스를 확장한다.

그렇기때문에 super를 통해 FragmentHostCallback의 생성자를 사용할 수 있는 것!

 

아~무튼~

new HostCallback()을 통해 Fragment를 보여줄 Activity의 정보를 넘겨주어 FragmentHostCallback 객체를 생성하였다!

 

[6] 다시 돌아온 createController()

 

다시 createController로 돌아가보면

/* FragmentController.java */

@NonNull
public static FragmentController createController(@NonNull FragmentHostCallback<?> callbacks) {
	return new FragmentController(checkNotNuull(callbacks, "callbacks == null")
}

방금 HostCallback을 통해 생성한 객체를 Null 체크를 한 후 FragmentController 객체를 생성하여 반환하는데

checkNotNull을 잠시 살펴보면

 

[7] checkNotNull

 

/* Preconditions.java */

public static @NonNull <T> T checkNotNull(@Nullable T reference, @NonNull Object errorMessage) {
	if (reference == null) {
    	throw new NullPointerException(String.valueOf(errorMessage));
    }
    return reference;
}

 

방금 HostCallback을 통해 객체를 생성하여 넘겨받았으니 null은 아니니 그대로 Callback을 반환한다!

null 체크가 끝나 반환받은 Callback은 FragmentController의 생성자를 통해 객체를 생성하게 되는데

 

[8] FragmentController 생성자

 

/* Fragmentcontroller.java */

private FragmentController(FragmentHostCallback<?> callbacks) {
	mHost = callbacks;
}

FragmentController 클래스의 전역변수인 FragmentHostCallback<?> 타입의 mHost에 전달받은 callback을 등록한 후, new 키워드를 통해 FragmentController의 객체가 드디어 생성된 것!

 

~ 중간 정리 ~

supportFragmentManager를 가져오기 위해 생성한 것

1) HostCallback

2) FragmentController

 

=> 가장 처음의 코드인 getSupportFragmentManager() 메소드를 실행할 수 있는 기본적인 토대(?)가 완성되었다.

/* FragmentActivity.java */

@NonNull
public FragmentManager getSupportFragmentManager() {
	return mFragments.getSupportFragmentManager();
}

 

 

HostCallback과 FragmentController를 통해 mFragments의 변수를 사용할 수 있게 되었다

 

[9] getSupportFragmentManager()

 

다음으로 알아 볼 것은 mFragments의 getSupportFragmentManager() 메소드!

/* FragmentController.java */

@NonNull
public FragmentManager getSupportFragmentManager() {
	return mHost.mFragmentManager;
}

mHost는 FragmentHostCallback의 타입을 가지고 있는데 FragmentHostCallback은 기본적으로 5개의 전역 변수를 가지고 있다.

/* FragmentHostCallback.java */

public abstract class FragmentHostCallback<E> extends FragmentContainer {
	@Nullable private final Activity mActivity;
    @NonNull private final Context mContext;
    @NonNull private final Handler mHandler;
    private final int mWindowAnimations;
    final FragmentManager mFragmentManager = new FragmentManagerImpl();
    
    ...
}

이전 코드들을 통해 mActivity, mContext, mHandler, mWindowAnimations은 값들을 지정해주었는데

mFragmentManager는 처음보며, new 키워드를 통해 FragmentManagerImpl의 객체를 생성한다.

ㄴ...넌...뭔데....!

 

[10] FragmentManagerImpl

 

/* FragmentManagerImpl.java */

class FragmentManagerImpl extends FragmentManager { }

~그냥 아무것도 없는 구현클래스임~

Package private implementation of FragmentManager.
All of the logic that used to be in this class has moved to FragmentManager itself.

설명을 보면 FragmentManager의 private한 구현 패키지인것임~ 그냥 FragmentManager 객체를 생성하였다고 보면됨~

왜냐면 FragmentManager를 확장하고 있는 클래스이기때문임~

 

/* FragmentController.java */

@NonNull
public FragmentManager getSupportFragmentManager() {
	return mHost.mFragmentManager;
}

mHost에서 mFragmentManager를 반환하면 드디어 Fragment를 관리하기위한... FragmentManager를 사용하기위한...

 

SupportFragmentManager를 사용하여 Activity와 연결되어 있는 Fragment를 관리할 수 있게되었다~!

 

< 총 정리 >

 

1) HostCallback 생성

2) FragmentController 생성

3) FragmentManager 생성

 

지금까지 사용한 변수들의 계층(?)을 살펴보면 위와 같다는 것을 알 수 있다.

그래서 mFragment를 통해 mFragmentManager를 가져올 수 있었음

 

근데 궁금한 점은 내가 사용할 Fragment는 어떻게 붙게되는거지?

이건 또 알아봐야겟지~~~~~~