[ kotlin ] Fragment 통신 - 공유 데이터 방식

·2023년 12월 10일
0

Mobile-Software

목록 보기
6/15
post-thumbnail

Fragment 통신

공유 데이터 방식

Fragment 들이 ViewModel 을 공유하하는 방법
중개자 역할 Host Activity 역할 부담이 줄어들음


LiveData : 데이터가 변경되었는지 관찰하는 역할,
외부 접근 차단을 위해 private 로 선언
Observer : Livedata 로부터 데이터 변경 알림을 받아 필요한 조치를 함




  • gradle 에 추가



  • CommonDataViewModel.kt
    - MutableLiveData는 데이터를 변경할 수 있는 LiveData의 구현체
    이를 통해 화면에 표시되는 데이터를 업데이트
    _myCount의 초기값은 0으로 설정
    - LiveData Getter: _myCount 를 읽기 전용으로 외부에 노출하기 위한 LiveData의 getter를 정의 -> 외부에서 _myCount를 직접 변경X, 오직 읽기만 가능
    - setCount(): 속성 업데이트 함수
    ViewModel을 통해 _myCount 값을 업데이트
    이 함수를 통해 _myCount의 값을 변경->해당 값이 myCount LiveData에 자동으로 알림을 보냄
    UI에서 이 값을 관찰하고 있는 경우 UI가 업데이트됩니다.
package com.example.fragmentexample2

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel

class CommonDataViewModel : ViewModel() {
    // 전달받는 값
    private var _myCount = MutableLiveData<Int>(0)

    // backUp muCount 
    val myCount: LiveData<Int> get() = _myCount
    
    fun setCount(cnt:Int){
        _myCount.value = cnt
    }
}



  • ClickFragment.kt
    - getCount() : MutableLiveData 타입 객체의 값을 가져 옴.
    - ViewModel 인스턴스 생성 : by lazy 를 이용해 처음 접근할 때만 생성하도록, CommonDataViewModel 의 객체를 생성하고, 액티비티에 속한 ViewModel로 지정
    - viewModel.setCount(currentCount) 를 호출하여 ViewModel의 setCount 메서드를 사용하여 ViewModel의 데이터를 업데이트
class ClickFragment : Fragment() {
    private val viewModel: CommonDataViewModel by lazy {
        ViewModelProvider(requireActivity()).get(CommonDataViewModel::class.java)
    }
    
    
    private var currentCount = 50
    private lateinit var binding: FragmentClickBinding

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        binding.countUpButton.setOnClickListener {
            currentCount += 5
            binding.countTextView.text = "Count = $currentCount"
            viewModel.setCount(currentCount)
        }
        binding.countDownButton.setOnClickListener {
            currentCount -= 5
            binding.countTextView.text = "Count = $currentCount"
            viewModel.setCount(currentCount)
        }
    }

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

        return binding.root
    }
}



  • ProgressFragment.kt
    - Observer 인터페이스를 구현하는 익명 객체를 생성하고, 이 객체를 myObserver라는 변수에 할당
    이 익명 객체는 Observer 인터페이스의 onChanged 메서드를 오버라이드하여 LiveData의 값이 변경될 때 호출되는 로직을 정의
    - 뷰 모델에서 myCount라는 LiveData를 observe하여 변경 감지 -> 해당 값의 변화에 따라 프로그래스 바와 레이팅 바를 업데이트합니다.
class ProgressFragment : Fragment() {
    private lateinit var binding: FragmentProgressBinding
    private val viewModel: CommonDataViewModel by lazy {
        ViewModelProvider(requireActivity()).get(CommonDataViewModel::class.java)
    }

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

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        val myObserver = object : Observer<Int> {
            override fun onChanged(cnt: Int) {
                if (cnt in 1..100) {
                    binding.progressBar.progress = cnt
                    binding.ratingBar.rating = cnt / 20f
                } else {
                    binding.progressBar.progress = 50
                    binding.ratingBar.rating = 2.5f
                }
            }
        }
        viewModel.myCount.observe(
            viewLifecycleOwner, myObserver
        )

    }
}



  • Main.kt
    메인 액티비티 부담을 줄여줌
package com.example.fragmentexample2

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.example.fragmentexample2.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
    }

}




< 결론 >

  • 가장 편해진 건 MainActivity 클래스 -> 중개 역할에서 벗어남
  • ClickFragment에서 선언한 Interface를 상속받을 필요가 없음.
  • ProgressFragment의 changeProgressBar()를 호출할 필요가 없음.



0개의 댓글