Issue
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?
Solution
To collect your flow in a Fragment, you can use:
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
importVM.state.collect { data ->
//do something
}
}
}
Answered By - bylazy
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.