본문 바로가기

android

Frgament 통신

[1]. Fragment-Fragment 또는 Fragment-Host Activity 간 통신을 하기 위한 간단한 방법으로는

Jetpack 의 ViewModel 라이브러리와 LiveData 라이브러리를 사용하는 방법이다.

ViewModel 은 기기의 구성 변경이 발생하여 컴포넌트가 재생성 되더라도 컴포넌트의 상태를 유지하기 위한 용도로 사용되며 LiveData 는 컨트롤러(예: Activity) 에 데이터 변경 사실을 알려주는 용도로 사용된다.

 

[2]. ViewModel 객체를 생성하기 위해서 ViewModelProvider 클래스를 사용하는데 이때 ViewModelProvider 의 생성자에는 ViewModelStoreOwner 라는 값을 넘겨줘야 한다. 이미 생성된 ViewModel 객체를 가져오거나 새로운 ViewModel 객체를 생성할 때 생성자를 통해 전달받은 ViewModelStoreOwner 내의 ViewModelStore 에 접근하여 이미 생성된 ViewModel 객체를 가져오거나, 새로운 ViewModel 객체를 생성하여 저장한다. 그렇기 때문에 Fragment 또는 Host Activity 가 같은 ViewModel 객체를 참조하기 위해서는 동일한 ViewModelProvider 생성자에 동일한 ViewModelStoreOwner 를 전달하여서 ViewModel 객체를 가져와야 한다.

 

[3]. Fragment-Host Activity 간 통신

 1. AFragment 에서 설정한 값을 MainActivity 에 알려주기 위해 AFragment 와 MainActivity 모두 ViewModel 을 생성할 때 ViewModelStoreOwner 를 Host Activity(MainActivity) 로 지정해준다.

 

 2. MainActivity 에서 AFragment 로 부터 변경 사항을 통지받기 위해 ViewModel 객체 내의 LiveData 를 관찰한다.

 

 3. AFragment 에서 ViewModel 내의 LiveData 에 값을 설정하는 순간 MainActivity 에서 등록한 LiveData 옵저버에도 통지가 가게되고 따라서 MainActivity 에서도 값이 변경되었음을 알아차릴 수 있게 된다.

 

MainActivity.kt

class MainActivity : AppCompatActivity() {
    private val binding by lazy { ActivityMainBinding.inflate(layoutInflater)}
    private val viewModel: MainViewModel by lazy { ViewModelProvider(this).get(MainViewModel::class.java)}

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

        initViews()
        initViewModel()
    }

    private fun initViews() {
        binding.aFragmentButton.setOnClickListener {
            supportFragmentManager.beginTransaction().apply {
                replace(R.id.fragment_container_view, AFragment())
                addToBackStack(null)
                commitAllowingStateLoss()
            }
        }
    }

    private fun initViewModel() {
        viewModel.item.observe(this) {
            Log.d("Communication", "MainActivity::${it}")
        }
    }
}

 

AFragment.kt

class AFragment : Fragment() {
    private var _binding: FragmentABinding? = null
    private val binding get() = _binding!!
    private val viewModel: MainViewModel by lazy { ViewModelProvider(requireActivity()).get(MainViewModel::class.java)}

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

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

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

        initViews()
        initViewModel()
    }

    private fun initViews() {
        binding.setItemButton.setOnClickListener {
            viewModel.setItem("A Fragment 에서 set item 버튼을 클릭했습니다.")
        }
    }

    private fun initViewModel() {
        viewModel.item.observe(viewLifecycleOwner) {
            Log.d("Communication", "AFragment::${it}")
        }
    }

}

 

MainViewModel.kt

class MainViewModel : ViewModel() {
    private val _item: MutableLiveData<String> = MutableLiveData()
    val item: LiveData<String> get() = _item

    fun setItem(item: String) {
        _item.value = item
    }
}

'android' 카테고리의 다른 글

Firebase Ream-Time Database Paging 처리  (1) 2022.10.25
DialogFragment width 조정  (0) 2022.10.22
Fragment Transaction 동작 분석  (0) 2022.10.10
registerForActivityResult 메서드의 동작과정  (0) 2022.02.03
context  (0) 2022.01.20