Adrian Witaszak
02/13/2023, 10:31 AMCasey Brooks
02/13/2023, 2:46 PMDispatchers.Main.Immediate
as the Dispatcher. Ballast currently uses Dispatchers.Default
as the default for everything
Try adding this into the viewModel configuration, and see if it helps:
.dispatchers(
inputsDispatcher = Dispatchers.Main.immediate,
eventsDispatcher = Dispatchers.Main.immediate,
sideJobsDispatcher = <http://Dispatchers.IO|Dispatchers.IO>,
interceptorDispatcher = Dispatchers.Default
)
Adrian Witaszak
02/13/2023, 2:54 PMCasey Brooks
02/13/2023, 2:56 PMwithContext(<http://Dispatchers.IO|Dispatchers.IO>)
Adrian Witaszak
02/13/2023, 4:17 PM<http://Dispatchers.IO|Dispatchers.IO>
in kotlin native, got Main, Default and Unconfined. Currently, for example signIn request i handle in the input, but it is not suspended fun. Scope is created in our sdk. But if it happens i need to make a request and start the scope in Ballast's InputHandler then i should use withContext(Dispatchers.Default)
? or sideJob maybe?Casey Brooks
02/13/2023, 4:29 PMDispatchers.Default
should be a fine replacement, it’s just about keeping long-running tasks off the main thread. Android will throw an exception if you try to make a network/DB call on the main thread, but for other platforms it may not be as strictly enforced but is still a good idea.
The decision of whether to wrap a block in withContext() { }
or move the call to a sideJob() { }
is basically down to whether you intend to suspend the Ballast VM’s queue while the call is being made. The sideJob is more boilerplate, but frees up the queue so other Inputs can be processed while the API call is still in progress.
Making the API call directly in the InputHandler (wrapped in withContext
) will change based on the InputStrategy. With FifoInputStrategy
, other Inputs that get sent while the API call is in progress will be queued and won’t be processed until the API completes, which may make the UI unresponsive. LifoInputStrategy
will cancel the signin request to handle new Inputs immediately. Playing with the KitchenSink example when looking at the Intellij plugin can help you get a feel for what exactly this looks likeAdrian Witaszak
02/14/2023, 3:32 PMAdrian Witaszak
02/14/2023, 3:48 PMinternal class LoginViewModel(
viewModelCoroutineScope: CoroutineScope,
displayErrorMessage: suspend (String) -> Unit,
onAuthSuccess: () -> Unit,
) : BasicViewModel<
LoginContract.Inputs,
LoginContract.Events,
LoginContract.State>(
config = BallastViewModelConfiguration.Builder()
.apply {
this += LoggingInterceptor()
logger = { PrintlnLogger() }
this += BallastSavedStateInterceptor(
LoginSavedStateAdapter()
)
}
.withViewModel(
initialState = LoginContract.State(),
inputHandler = LoginInputHandler(),
name = LoginViewModel::class.simpleName,
)
.dispatchers(
inputsDispatcher = Dispatchers.Main.immediate,
eventsDispatcher = Dispatchers.Main.immediate,
sideJobsDispatcher = Dispatchers.Default,
interceptorDispatcher = Dispatchers.Default
)
.build(),
eventHandler = LoginEventHandler(
displayErrorMessage = displayErrorMessage,
onAuthSuccess = onAuthSuccess,
),
coroutineScope = viewModelCoroutineScope,
)
Casey Brooks
02/14/2023, 4:15 PM.collectAsState(Dispatchers.Main.immediate)
. Or else populate the text field with a mutableStateOf
and mirror that value in the VMubuntudroid
10/30/2023, 7:28 PMTextFieldValue
instead of String
in the state might just fix things for you as TextFieldValue also stores cursor position and composition state.
With which solution did you settle @Adrian Witaszak?Adrian Witaszak
10/31/2023, 12:17 AM