Fragment Alternate constructor

홍성덕·2024년 7월 17일
class SearchFragment : Fragment(R.layout.fragment_search) {

    private var _binding: FragmentSearchBinding? = null
    private val binding get() = _binding!!

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        _binding = FragmentSearchBinding.inflate(inflater, container, false)
        val view = binding.root
        return view
    }
    
    // ...
}

위의 코드를 보면 Fragment의 생성자로 layoutId를 넘겨주고 있다.
습관적으로 이렇게 사용해왔는데 이걸 왜 사용해야 하는지 모르고 사용하다 보니, 잘못 사용하고 있다는 것을 알게 되었다.

Fragment(R.layout.fragment_search)의 내부 코드를 보면 이렇다.

//... (설명 주석 생략)
@ContentView
public Fragment(@LayoutRes int contentLayoutId) {
	this();
	mContentLayoutId = contentLayoutId;
}

주석 설명에 따르면 이것은 Fragment의 Alternate constructor(대체 생성자)로 onCreateView()에 의해 inflate될 레이아웃을 제공하기 위함이 목적이다. 위 코드의 mContentLayoutId는 Fragment class의 프로퍼티인데, 이 프로퍼티를 우리가 넘겨준 contentLayoutId 생성자 파라미터로 초기화하고 있다.

//... (설명 주석 생략)
@MainThread
@Nullable
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, 
		@Nullable Bundle savedInstanceState) {
	if (mContentLayoutId != 0) {
    	return inflater.inflate(mContentLayoutId, container, false);
    }
    return null;
}

mContentLayoutId가 어디서 사용되는지 살펴보면, onCreateView()메소드에서 레이아웃을 inflate하는데 사용되고 있다. 즉, Alternate constructor로 contentLayoutId를 넘겨주면, mContentLayoutId != 0 조건이 true이므로, inflate가 자동으로 이루어진다. 그래서 개발자가 직접 onCreateView()를 override하여 또다시 레이아웃을 inflate해 줄 필요가 없다.

// 1차 수정 후
class SearchFragment : Fragment(R.layout.fragment_search) {

    private var binding: FragmentSearchBinding? = null
    
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        
        //...
    }
    //...
}

수정한 코드는 위와 같다.

하지만 이렇게 되면 binding 객체는 계속 null을 유지하게 된다. binding 객체를 통해서 레이아웃의 View에 접근해야 하는데 이렇게 되면 접근할 수가 없다. bind() 메소드를 사용하여 이를 해결할 수 있다.

위와 같이, 안드로이드 공식문서에서도 이미 layout이 inflate 되었다면 bind() 메소드를 대신 호출할 수 있다고 설명하고 있다.

// 2차 수정 후
class SearchFragment : Fragment(R.layout.fragment_search) {

    private var binding: FragmentSearchBinding? = null
    
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        
        binding = FragmentSearchBinding.bind(view)
    }
    //...
}

참고자료

https://developer.android.com/topic/libraries/view-binding#fragments
https://github.com/android/architecture-components-samples/blob/master/ViewBindingSample/app/src/main/java/com/android/example/viewbindingsample/BindFragment.kt#L36-L41

profile
안드로이드 주니어 개발자

0개의 댓글