BaseActivity에 대한 고찰 (의존성 톺아보기)

GongBaek·2024년 4월 17일
0

🎉 의존성

의존성이란?

----------

코드에서 두 클래스간의 연결 혹은 관계를 말합니다.
클래스 A가 다른 클래스 B를 이용할 때 A가 B에 의존한다고 말할 수 있죠.

위 사진을 보면 LoginActivity가 LogInViewModel에 의존하는 화살표의 모습을 보실 수 있습니다.

우리는 이렇게 계층을 분리하고 유지보수나 메모리 누수 방지 등을 위해 의존성을 활용합니다.

의존성이란?

----------
좀 더 쉽게 알아볼까요?

저희는 김치찌개, 김치전을 만들기 위해 김치를 활용합니다!
김치찌개와 김치전은 김치에 의존한다고 볼 수 있죠?

하지만 된장찌개의 경우는 어떨까요? 의존이 불가능하죠?
이렇게 의존이 어려운데, 이미 김치가 들어가버린다면?
저희는 그걸 하나하나 건져야합니다~~


만약 고추에 의존한다면?
훨씬 범용적으로 변했죠?! 이런식으로 의존하는 모습을 볼 수 있습니다.
이에 대해 좀 더 깊게 다뤄볼까 하는데요~~

BaseActivity란?

----------

Activity에서 Binding과 같이 중복되는 코드가 꽤 있습니다.
이러한 부분들을 편하게 사용하기 위해 확장 액티비티를 두는 방식입니다.

사용하는 방법부터 알아볼까요?
우선 아래와 같이 BaseActivity를 작성해 줍시다.
늘 사용하는 binding을 자연스럽게 붙여줍니다.

abstract class BaseActivity<B : ViewDataBinding>(
    @LayoutRes private val layoutResId: Int,
) : AppCompatActivity() {
    private var _binding: B? = null
    val binding get() = _binding!!

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        _binding = DataBindingUtil.setContentView(this, layoutResId)
    }
}

저는 거의 binding의 역할만 한다고 생각해서
추상 클래스명을 BaseActivity로 명명하였습니다.

평상시에 사용하는 MainActivity를 보면 AppCompatActivity를 볼 수 있죠?
평상시와 같이 binding도 늘 하던 것처럼 자연스럽게 초기화를 진행해줍니다.

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        setBottomNavigationView()
    }

하지만 BaseActivity를 사용하는 이유가 뭐라고 했는지 기억 나시나요?

바로 중복되는 코드를 줄여주기 위해서입니다.

아래와 같이 BaseActivity로 선언해주시고 <>안에 바인딩을 대신 넣어줍니다.
괄호 안에 레이아웃이 가진 id를 함께 기입합니다.

class MainActivity : BaseActivity<ActivityMainBinding>(R.layout.activity_main) {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(binding.root)

        setBottomNavigationView()
    }

이런식으로 코드가 짧아진 모습을 볼 수 있습니다.
BindingFragment또한 아래와 같이 간단히 사용할 수 있습니다.

abstract class BindingFragment<B : ViewDataBinding>(
    @LayoutRes private val layoutResId: Int,
) : Fragment() {
    private var _binding: B? = null
    val binding get() = _binding ?: error("error: binding is null")

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

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }
}

다시, 의존성.

----------

하지만 저희가 사용하는 Activity는 BaseActivity를 활용함으로써 의존이란 것을 하게 됩니다.
만약 BaseActivity에 추가되었으면 하는 공통 코드가 많아진다면,
이렇게 많은 기능을 하는 만능(?) BaseActivity가 만들어지겠죠?

이는 과연 좋을 것인지 생각해봐야 합니다.

  • Activity에 공통되는 기능이 많을수록 점점 BaseActivity가 무거워집니다.
    • 이것도 넣어야 할 것 같고, 저것도 넣어야 할 것 같고~~
    • 각 뷰마다 많은 기능이 필요할 것이고, 겹치는 내용이 많다면 계속해서 내용이 증가합니다.
  • 다른 개발자들도 내가 추가한 BaseActivity를 사용할 수 있습니다.
    • 이 사람들은 어떤 기능이 추가되었는지 모두 인지할까?
    • BaseActivity와 중복되는 코드가 발생할 수 있습니다.
  • BaseActitivy에 대한 의존성이 많은 Activity에 퍼지게 됩니다.
    • 만약 여기서 오류가 발생한다면?
    • 기능을 수정해야 할 일이 발생한다면?

이러한 문제들이 있음에도~
실제로 Boilerplate Code가 될 수 있으니 BindingActivity 정도는 충분히 쓸만합니다!!
대신 다른 기능을 추가할 때는? 무작정 추가하지 않고 경계를 할 필요가 있다고 볼 수 있습니다.

번외

----------

그렇다면 어떻게 해야 하느냐?

이럴 때는 확장함수를 이용할 수도 있습니다.
확장함수를 통해 재사용되는 코드를 줄이는 것입니다.

But, 이 또한 의존도를 증가시키는 일이기에 다시 한 번 생각해볼 필요가 있습니다~~

이에 대해 정리된 글이 있으니 읽어보셔도 좋을듯합니다 🤭

profile
Junior Android Developer

0개의 댓글

관련 채용 정보