Home > database >  How can I handle the state value on change without using Composable in Kotlin?
How can I handle the state value on change without using Composable in Kotlin?

Time:02-04

I have a VM and a fragment. I want to handle the change of state.value in the fragment. How can I do that. Here is the fragment:

AndroidEntryPoint
class ImportFragment : Fragment() {
    private val importVM by viewModels<ImportFragmentVM>()
    lateinit var importButton: Button
    lateinit var createButton: Button
    lateinit var tab: TabLayout
    lateinit var createItems: Group
    lateinit var importItems: Group
    lateinit var longUrl: EditText

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        val view = inflater.inflate(R.layout.import_fragment, container, false)
        
        importButton = view.findViewById(R.id.importButton)
        createButton = view.findViewById(R.id.createButton)
        tab = view.findViewById(R.id.tab)
        createItems = view.findViewById(R.id.createGroup)
        importItems = view.findViewById(R.id.importGroup)
        longUrl = view.findViewById(R.id.longurl)
        createItems.isVisible = false
        Timber.d("tab position:"   tab.selectedTabPosition)
        tab.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {

            override fun onTabSelected(tab: TabLayout.Tab) {
                when (tab.position) {
                    0 -> {
                        createItems.isVisible = false
                        importItems.isVisible = true
                        Timber.d("position 0")
                    }
                    1 -> {
                        createItems.isVisible = true
                        importItems.isVisible = false
                        Timber.d("position 1")
                    }
                }
            }

            override fun onTabUnselected(tab: TabLayout.Tab?) {
            }

            override fun onTabReselected(tab: TabLayout.Tab?) {
            }
        })
        longUrl.addTextChangedListener(object : TextWatcher {

            override fun afterTextChanged(s: Editable) {}

            override fun beforeTextChanged(
                s: CharSequence, start: Int,
                count: Int, after: Int
            ) {
            }

            override fun onTextChanged(
                s: CharSequence, start: Int,
                before: Int, count: Int
            ) {
                importVM.updateInput(longUrl.text.toString())
            }
        })

        createButton.setOnClickListener {
            val x = importVM.submit()
            if (x is ImportFragmentVM.ImportUIState.Success)
                Timber.d("assadads")
        }
        return view
    }

}

And here is the VM for this fragment:

@HiltViewModel
class ImportFragmentVM @Inject constructor(
    private val service: UrlService
) : ViewModel() {
    sealed interface ImportUIState {
        data class PendingUserInput(val longUrl: String) : ImportUIState
        object Loading : ImportUIState
        object Success : ImportUIState
        data class PartialSuccess(val urlKey: UrlKey, val urlApiKey: UrlApiKey) : ImportUIState
        object Error : ImportUIState
        object Invalid : ImportUIState

    }

    val _state = MutableStateFlow<ImportUIState>(PendingUserInput(""))
    val state: StateFlow<ImportUIState> = _state

    fun updateInput(longUrl: String) {
        check(_state.value is PendingUserInput) { "You can't be in update" }
        Timber.d("longurl:"   longUrl)
        _state.value = PendingUserInput(longUrl)
    }

    fun submit():ImportUIState {

        val longUrl = state.value.run {
            check(this is PendingUserInput) { "You can't be in update when submitting" }
            longUrl
        }
        Timber.d("sunt in submit")
        _state.value = Loading
        Timber.d("value is"   state.value)

        viewModelScope.launch(Dispatchers.IO) {
            val result = service.shortenUrl(longUrl)
            if (result is ShortenRequestOutcome.Failed)
                _state.value = Error
            if (result is ShortenRequestOutcome.Invalid)
                _state.value = Invalid
            if (result is ShortenRequestOutcome.Success)
                _state.value = Success
        }
        return state.value
    }
}

For example I want to show a dialog/toast based on the state.value, and I don't know how to find out in the fragment when the value has changed. Any ideas?

CodePudding user response:

To collect your flow in a Fragment, you can use:

viewLifecycleOwner.lifecycleScope.launch {
    viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
        importVM.state.collect { data ->
            //do something
        }
    }
}
  •  Tags:  
  • Related