본문 바로가기

개발일기

MVVM 모델로 나아가기 1단계 : Fragment

...는 절반의 성공. 하지만 step by step 나아가는 것! 언제나 조급해하지 말자. 무엇이든 멈추지만 않으면 된다는 마음가짐으로!

앞서 구조를 뜯어고치고자 결심한 계기는 기존에는 완전 초보로 Activity에 모든 것을 몰아넣었지만, "안드로이드스러운" 개발을 위해 MVVM을 적용해보려 했다. 액티비티들의 연쇄로 무겁고 Intent와 Static 선언을 통한 데이터 통신보다 간단하고 가벼운 방법을 찾고 싶기도 했고.

 

하여 우선 액티비티로만 이루어져 있던 것을 Fragment로 바꿔주는 작업을 시작했다.

MainActivity 에서 버튼식으로 나아가던 액티비티들이 결국 DrawerLayout과 본질적으로 다를 게 없으니, 그 페이지들은 프래그먼트로 뷰를 올리자는 것. 하는 김에 원래 MainActivity였던 것도 MainFragment로 내보냈다. Mainactivity는 완전 FrameLayout으로.

 

하지만 컨셉 자체는 Fragments 간에 전환이 이루어지는 게 아니라 중심은 메인이 되어야 하기 때문에 FragmentA, B 등에서 뒤로 가기 버튼을 누르면 MainFragment 뷰를 띄우기 위해 인터페이스로 FragmentChangeListener를 넣어주었다.

FragmentChangeListener.kt

// ref: https://stackoverflow.com/questions/21228721/how-to-replace-a-fragment-on-button-click-of-that-fragment

interface FragmentChangeListener {
    fun replaceFragment(fragment: Fragment)
}

인터페이스를 MainActivity에 오버라이딩 시켜준다.

MainActivity.kt

class MainActivity : AppCompatActivity(), View.OnClickListener, FragmentChangeListener {

...

    override fun replaceFragment(fragment: Fragment) {
        val transaction = supportFragmentManager.beginTransaction()
        transaction.replace(R.id.main_container, fragment, fragment.toString())
            .addToBackStack(fragment.toString())
            .commit()
    }
}

MainFragment의 모습.

MainFragment.kt

class MainFragment : Fragment(), View.OnClickListener {
    private var _binding: MainFragmentBinding? = null 
    private val binding: MainFragmentBinding get() = _binding!!

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? =
        MainFragmentBinding.inflate(inflater, container, false).also {
            _binding = it
        }.root

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        binding.mainFragTitle.text = "Main Window"
        binding.mainFragCardViewTeeTime.setOnClickListener(this)

        binding.mainFragCardViewTeeTime.setOnClickListener(this)
        binding.mainFragCardViewScore.setOnClickListener(this)
    }
    ...

    override fun onClick(v: View?) {
        when (v?.id) {
            R.id.main_frag_cardView_A -> {
                val fragmentA = FragmentA()
                val fc: FragmentChangeListener = activity as FragmentChangeListener
                fc.replaceFragment(fragmentA)
            }
            R.id.main_frag_cardView_B -> {
                val fragmentB = FragmentB()
                val fc: FragmentChangeListener = activity as FragmentChangeListener
                fc.replaceFragment(fragmentB)
            }
        }
    }
}

 

절반의 성공인 이유는 Fragment를 올리기는 했는데 ViewModel을 적용한 MVVM은 아니기 때문이다. 네트워크 쪽 작업을 우선 마무리 짓고 진정한 MVVM의 길로 나아갈 계획이다. 어차피 말은 이렇게 해도 두 작업은 병행할 수밖에 없지만. 결국 코루틴 사용이 관건인데... 갈 길이 멀다. ㅠㅠ 바쁘다 바ㅃㅏ