Channel, receiveAsFlow 차이

yeji·2022년 9월 12일
0

Channel로 값을 전송/수신 하려면 같은 CoroutineScope를 사용해야 한다.

1. Channel을 Flow로 변환하여 데이터를 방출하는 방법

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}")

                    }
                }
            }
        }

    }
}

2. Flow로 변환하지 않고 Channel로 사용하고 싶은 경우?

-> 같은 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}")
                }


            }
        }
}

code : https://github.com/yezji/FlowPractice

profile
🐥

0개의 댓글