본문 바로가기
개발/Android

[Android] MVVM + Navigation Graph 사용 시 프래그먼트 이동 처리 방법

by JhDroid 2021. 4. 9.
728x90

Navigation Graph 사용 시 프래그먼트 이동

  • Navigatino Graph를 사용해 프래그먼트를 연결하면 자동으로 action을 생성해 줌

연결 예시

  • 예시 이미지는 timetable -> schedule Fragment로 연결했고 이렇게 연결해주면 자동으로 <fragment> 태그 안에 <action> 태그가 생성됨
 <fragment
    android:id="@+id/timetable_fragment"
    android:name="com.jhdroid.sigan2.ui.timetable.TimetableFragment"
    android:label="@string/timetable"
    tools:layout="@layout/fragment_timetable" >
    <action
        android:id="@+id/action_timetable_fragment_to_schedule_fragment"
        app:destination="@id/schedule_fragment" />
</fragment>
  • action은 자동으로 생성되는 <FragmentName>Directions 클래스를 통해 가져올 수 있고, 생성된 Action을 이용해 프래그먼트를 이동할 수 있음
val action =
    TimetableFragmentDirections.actionTimetableFragmentToScheduleFragment()
findNavController().navigate(action)

 

MVVM에서 action 처리

  • MVVM 패턴을 적용 중일 때 이 action 처리를  google의 architecture-samples 프로젝트를 참고해서 작업해보겠습니다.
  • Event 처리를 위한 Event 클래스와 EventObserver 생성
open class Event<out T>(private val content: T) {
    @Suppress("MemberVisibilityCanBePrivate")
    var hasBeenHandled = false
        private set // Allow external read but not write

    fun getContentIfNotHandled(): T? {
        return if (hasBeenHandled) {
            null
        } else {
            hasBeenHandled = true
            content
        }
    }

    fun peekContent(): T = content
}

class EventObserver<T>(private val onEventUnhandledContent: (T) -> Unit) : Observer<Event<T>> {
    override fun onChanged(event: Event<T>?) {
        event?.getContentIfNotHandled()?.let {
            onEventUnhandledContent(it)
        }
    }
}
  • ViewModel에서 Event를 받는 LiveData 객체 생성 및 이벤트 처리를 위한 함수 추가
class TimetableViewModel(
    private val repo: Repository
) : BaseViewModel() {

    ...

    private val _addScheduleEvent = MutableLiveData<Event<Unit>>()
    val addScheduleEvent: LiveData<Event<Unit>> = _addScheduleEvent

    fun addScheduleEvent() {
        _addScheduleEvent.value = Event(Unit)
    }
}
  • View에 상태 전달을 위한 함수 연결
<com.google.android.material.button.MaterialButton
    android:id="@+id/add_schedule_btn"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@android:color/transparent"
    android:onClick="@{() -> viewModel.addScheduleEvent()}"
    android:text="@string/timetable_add_schedule"
    android:textColor="@color/color_primary"
    android:textStyle="bold"
    app:layout_constraintBottom_toBottomOf="@+id/current_month_txt"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintTop_toTopOf="@+id/current_month_txt" />
  • Fragment에서 Event LiveData 객체의 상태가 변경될 때 action 처리하도록 작업
class TimetableFragment : Fragment() {

    private lateinit var binding: FragmentTimetableBinding
    private val viewModel by viewModel<TimetableViewModel>()

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

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        binding.lifecycleOwner = this
        binding.viewModel = viewModel

        setupNavigation()
    }

    private fun setupNavigation() {
        viewModel.addScheduleEvent.observe(requireActivity(), EventObserver {
            val action =
                TimetableFragmentDirections.actionTimetableFragmentToScheduleFragment()
            findNavController().navigate(action)
        })
    }
}

 

* 글에 틀린 부분이 있으면 댓글 부탁드립니다 :D

 

728x90