• Breaking News

    [Android][timeline][#f39c12]

    Sunday, January 30, 2022

    ViewModels & Compose: State/StateFlow/Lifecycle Android Dev

    ViewModels & Compose: State/StateFlow/Lifecycle Android Dev


    ViewModels & Compose: State/StateFlow/Lifecycle

    Posted: 29 Jan 2022 08:52 PM PST

    Rant/sanity check post about how to expose UI state/data from ViewModels when using Compose. Also, stuff gets annoying when Lifecycle needs to be involved.

    • I really like the idea of using State<T>s in ViewModels and not exposing Flows / StateFlows to composables (no additional boilerplate required for use in composables, works seamlessly)
    • But doing so really depends on how your business logic data is structured; if it is backed by a cold Flow or a hot Flow doing expensive work in the flow producer

    Case 1: Non-Flow Data Source

    Simplest case - no Flows in the picture, so State is an attractive option:

     class FooViewModel( private val getFooContent: GetFooContent ): ViewModel() { var state by mutableStateOf(FooState.Loading) private set init { viewModelScope.launch { state = getFooContent() // suspend func } } } 

    Case 2: Cold Flow Data Source

    If business layer data is backed by some cold Flow (or maybe even a hot Flow that isn't doing any expensive work like observing GPS, etc):

    • could use viewModelScope to collect the Flow and write to the State
    • although viewModelScope is larger than lifecycleScope of the corresponding Activity /Fragment, collecting the Flow here regardless of Lifecycle pause/resume could be ok if the source is cold or not doing expensive work when collecting

     class FooViewModel( private val coldFooContents: ColdFooContents ): ViewModel() { var state by mutableStateOf(FooState.Loading) // private set init { viewModelScope.launch { coldFooContents .onEach { state = it } .launchIn(viewModelScope) // viewModelScope should be ok? } } } 

    Case 3: Hot Flow Data Source

    If your data source implementation changes to a hot data source that runs expensive operations, such as reading GPS updates, etc, viewModelScope becomes too broad of a scope:

     class FooViewModel( private val hotFooContents: HotFooContents ): ViewModel() { var state by mutableStateOf(FooState.Loading) // private set init { viewModelScope.launch { hotFooContents .onEach { state = it } // viewModelScope keeps expensive operations running // need to involve Lifecycle to pause/resume work .launchIn(viewModelScope) } } } 

    Options in this case:

    • Option 1: Just expose Flow/ StateFlow in this case and use the Flow.flowWithLifecycle() APIs. This is SUPER awkward in Compose because conversion of StateFlow to State requires boilerplate:

     // Ugh? @SuppressLint("StateFlowValueCalledInComposition") @Composable fun <T> StateFlow<T>.collectStateWithLifecycle( lifecycle: Lifecycle = LocalLifecycleOwner.current.lifecycle, minActiveState: Lifecycle.State = Lifecycle.State.STARTED ): State<T> = remember(this, lifecycle) { this.flowWithLifecycle(lifecycle, minActiveState) }.collectAsState(initial = this.value) // !! StateFlowValueCalledInComposition 

    • Option 2: Observe your hot data source in a LifecycleObserver, update a cache, and observe the cache in the ViewModel instead (obfuscate the fact that the original data is hot). You're back to the cold Flow case:

     // Attach HotDataLifecycleObserver to Activity/Fragment class HotDataLifecycleObserver( private val hotFooContents: HotFooContents private val updateCache: UpdateFooContentsCache ): DefaultLifecycleObserver { fun onCreate(owner: LifecycleOwner) { // collect hotFooContents with // repeatOnLifecycle/flowWithLifecycle APIs here // and call updateCache() // Don't forget to clear the cache at some point } } class FooViewModel( private val coldCache: ColdFooContentsCache ): ViewModel() { var state by mutableStateOf(FooState.Loading) // private set init { viewModelScope.launch { coldCache .onEach { state = it } .launchIn(viewModelScope) // viewModelScope should be ok } } } 

    Given all this, the choices are something like:

    • choose State<T> vs Flow/StateFlow + LifecycleObserver based on how business layer data is structured, OR
    • just expose StateFlows for all cases and deal with all the gross boilerplate, OR
    • use LaunchedEffect or some combination of side-effect APIs to read data in a smaller CoroutineScope??

    This stuff is super important and yet feels a little hand-wavy, awkward, and frustrating; maybe documentation/APIs or both need to improve (see this issue).

    Does anyone else share in the frustration, or otherwise have thoughts about this? What strategies do you use in your projects?

    Thanks for reading!

    submitted by /u/nebulasmoothie
    [link] [comments]

    Ever wonder how Android Access View Items evolve over the years?

    Posted: 30 Jan 2022 02:30 AM PST

    How to detect autoclick on layout in java?

    Posted: 29 Jan 2022 10:18 PM PST

    Hi guys,

    I'm wondering, how to detect autoclick on a layout without to use any services. Maybe intercept clicks and check gestures and click paramteres? What do you think? Is is worth to implement some code or the autoclicker apps are nowadays too clever that they can simulate clicks like it would be a human click?

    Thanks!

    submitted by /u/frinor
    [link] [comments]

    Creating an app on fiverr

    Posted: 29 Jan 2022 08:11 PM PST

    Hi all,

    I have an app idea but I have zero experience in coding. I was thinking of hiring someone overseas on fiverr for development of an app. A quotes based app, where the app generates one quote per day. It would have other details as ability to set when the quote is issued in the day, acknowledgement page, add some ads on a page, ability to pay and remove ads. I see pricing coming in for me around $400-$800 for the app. Has anyone done created an app off Fiverr and how did it go? Is this price point reasonable for a daily quotes app or is it going to lead to a low quality app?

    Thanks!

    submitted by /u/ksing_king
    [link] [comments]

    No comments:

    Post a Comment

    Fashion

    Beauty

    Travel