Channel로 값을 전송/수신 하려면 같은 CoroutineScope를 사용해야 한다.
Channel을 Flow로 변환하여 데이터를 방출한다면 다른 CoroutineScope를 사용해도 잘 동작한다.
class NewViewModel : ViewModel() {
...
private val _channel = Channel<String?>()
val channel = _channel.receiveAsFlow() // channel을 flow로 변환하여 사용
suspend fun setChannel(string: String?) { _channel.send(string) }
}
class NewFragment : Fragment() {
...
private val newViewModel: NewViewModel by activityViewModels<NewViewModel>()
...
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
...
lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
launch {
/**
* Flow인 경우 다른 coroutine scope여도 받아올 수 있다!!!
* - MainViewModel에서 channel.send하는 경우가 다른 coroutine scope인 것이다.
* ex.
* viewModelScope.launch {
// setSharedFlow(null)
// setChannel(null)
// setStateFlow(null)
// }
*/
newViewModel.channel.collect { str ->
binding.tvChannel.text = str
Log.d("yezzz NewFragment", "channel: ${str}")
}
}
}
}
}
}
-> 같은 CoroutineScope임을 지정할 수 있도록 externalScope로 빼주는 작업이 필요하다!
-> withContext(externalScope.coroutineContext)
val externalScope = CoroutineScope(Dispatchers.Main)
class MainViewModel : ViewModel() {
...
private val _channel = Channel<String?>()
val channel: Channel<String?> get() = _channel
suspend fun setChannel(string: String?) = withContext(externalScope.coroutineContext) {
_channel.send(string)
}
}
class MainActivity : AppCompatActivity() {
...
private lateinit var mainViewModel: MainViewModel
...
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
...
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
/**
* Channel인 경우 다른 coroutine scope면 받아올 수 없다!!!
* - 그래서 => externalScope.launch로 같은 coroutine scope로 동작하게끔 함!!!
* - MainViewModel에서 channel.send하는 경우가 다른 coroutine scope인 것이다.
* ex.
* viewModelScope.launch {
// setSharedFlow(null)
// setChannel(null)
// setStateFlow(null)
// }
*/
externalScope.launch {
// Channel인 경우 다른 coroutine scope면 받아올 수 없다!!!
val str = mainViewModel.channel.receive()
binding.tvChannel.text = str
Log.d("yezzz MainActivity", "channel: ${str}")
}
}
}
}