The ONLY Correct Way to Load Initial Data In Your Android App?

แชร์
ฝัง
  • เผยแพร่เมื่อ 11 ม.ค. 2025

ความคิดเห็น • 166

  • @PhilippLackner
    @PhilippLackner  3 หลายเดือนก่อน +55

    Little addition: Depending on your situation you may want to use SharingStarted.Lazily instead of WhileSubscribed, especially if you want to keep the value of the flow when the app goes in the background

  • @skydoves
    @skydoves 3 หลายเดือนก่อน +64

    Thank you so much for featuring my article on your video and your shoutout!
    Great and clear explanation. I really like your approach of verifying solutions through unit tests :)

    • @etherxi
      @etherxi 3 หลายเดือนก่อน

      Really awesome info. Thanks a lot @skydoves and @PhilippLackner

    • @deletedchanneI
      @deletedchanneI หลายเดือนก่อน +1

      good for those migrating from MVP architecture, thx!

  • @npacebg
    @npacebg 3 หลายเดือนก่อน +28

    You can mitigate the downside of approach #2 with a simple and lazy (pun intended) workaround - in unit tests, just lazy-init the ViewModel with `by lazy` instead of putting it in a @Before function. That way, the loading on init would not trigger until the unit test body references the ViewModel. You can still use @Before to set up mocks and test doubles, just don't touch the ViewModel.

    • @marta_na_moto
      @marta_na_moto 3 หลายเดือนก่อน +3

      Dude... this is so simple.. I am mind blown. Wtf XD

  • @Shakenbeer
    @Shakenbeer 3 หลายเดือนก่อน +115

    Imagine next scenario: Screen A with a list, which is loaded on entering the screen, screen B is details screen. If you spend more than 5 seconds on a screen B, when you go back, screen A will load data again. Third approach is the worst one.

    • @luongtran7837
      @luongtran7837 3 หลายเดือนก่อน

      Well, in that case, I think we can either increase the threshold (if you believe the data needs to be reloaded after some time) or simply change the strategy to SharingStarted.Lazily. As mentioned, we have full control over the behavior based on our needs

    • @Mackovitch
      @Mackovitch 3 หลายเดือนก่อน

      I agree. The same problem also arises when the app goes into the background while not leaving the Screen A with the initial data.
      One solution would be to use SharingStarted.Eagerly or Lazily. To my best knowledge, it will always keep the data in the hot flow. The first one will do it at init time of the flow so not the best solution (similar to solution 2 > init block). Therefore the Lazily approach seems to be the best: it will trigger the flow only once and only when the first subscriber comes along.

    • @imSagarMalhotra
      @imSagarMalhotra 3 หลายเดือนก่อน +19

      I've already tested what you're saying here. And you're correct!!

    • @luongtran7837
      @luongtran7837 3 หลายเดือนก่อน

      @@Shakenbeer Well, in that case, I think we can either increase the threshold (if you believe the data needs to be reloaded after some time) or simply change the strategy to SharingStarted.Lazily. As mentioned, we have full control over the behavior based on our needs.

    • @binqiangliang4745
      @binqiangliang4745 3 หลายเดือนก่อน +29

      You are right, there is no perfect way to load initial data, everyone should choose the most appropriate method according to the actual situation. For me, the second way is good and sufficient.

  • @lalobarrios16
    @lalobarrios16 3 หลายเดือนก่อน +11

    All these steps got pros and cons. The wisest idea is to get the best solution for your own problem.

  • @asifsohanz
    @asifsohanz 3 หลายเดือนก่อน +10

    I follow the first approach because it works well for test cases. To avoid the usual issues, I make sure that data is loaded only once by using a flag inside base ViewModel and call the load data function inside the scope. This prevents the function from being called multiple times during recomposition.

    • @PhilippLackner
      @PhilippLackner  3 หลายเดือนก่อน +6

      That's Also a way to do it 🙌

    • @Slodin
      @Slodin 19 วันที่ผ่านมา

      this is what I thought the 3rd way would be lmao...but the downside of this is each viewModel needs a flag for this, which I'm not a big fan of. I think the 2nd way with lazy is one of the better ones. 3rd way is good if you want to refetch to get rid of stale data, our application is fresh data mission critical, so technically 3rd way is the best.

  • @Mike-er2ih
    @Mike-er2ih 3 หลายเดือนก่อน +6

    Both 2 and 3 seems decent. In #1 the problem is also mitigated a lot of time by having data cached locally (which is common). So if for example most recently stored load is younger then X hours you use local data (unless user explicitly refreshes or something). This helps with config changes as only local database is accessed.

    • @amalhanaja
      @amalhanaja 3 หลายเดือนก่อน

      Agreed, either we can utilize the SavedStateHandle

  • @hosenalzuhile3019
    @hosenalzuhile3019 3 หลายเดือนก่อน +1

    I solved this issue by a quite different approach, I created a data wrapper class called Resource, and Resource has a function called fetch(FetchType (could be Fetch, Refresh Or Invalidate), a lamda that fetches the data (calling to the usecase)
    Then based on the type of fetching it knows if should I call the lambda or not, ex: if I loaded the data already and called Fetch, then it won't call the lambda, If I loaded the data and called Refresh, it will try to fetch new data and update the exist one, but if it failed it will keep the exist one
    And the Invalidate case will delete the exist data and try to fetch new one even if the data is loaded, because it's invalid anymore
    This is very helpful and clear in code.

    • @Shivam-ed5fn
      @Shivam-ed5fn 3 หลายเดือนก่อน

      Can you please share your code somewhere on discord or wherever you say.

  • @2011fallenstar
    @2011fallenstar 2 หลายเดือนก่อน +1

    Advice: if you adopt this way of loading data, wrap all shareIn calls in extension method, otherwise you may miss some parameters next time. Also relying on Flow for your business logic is tricky. Flows are very hard to understand, I would even say impossible

  • @BenBastami
    @BenBastami 3 หลายเดือนก่อน +5

    Just to share, there is a way to test with the second approach, (when using the ViewModel init block to load data), all you need to do is delay the ViewModel initialisation, in other words, do not initiate the ViewModel in your test class setup function, rather do it in each of your actual tests. in my view this is the most naturally way and less boiler plate in code, although the launched effect with a flag should work but I think that is a bit unnatural compared to using the given ViewModel init block for free. (sadly option 3 using 5 second delay should be avoided others explained why already :) ,

  • @cslesin5750
    @cslesin5750 3 หลายเดือนก่อน +5

    Nice sharing. Personally, I'd just go with the init block approach. The third one just looks hard to understand.

  • @DaleHawkins
    @DaleHawkins หลายเดือนก่อน

    Thanks!

  • @hippiefish7928
    @hippiefish7928 3 หลายเดือนก่อน

    Hi Philipp, just wanted to thank you for all your hard work ... I am using your videos to help me learn Android Compose/Kotlin development, very informative and enjoyable videos ... Thanks Philipp ... (Mark Suckerberg 😂)

  • @foivosstamopoulos9709
    @foivosstamopoulos9709 2 หลายเดือนก่อน +1

    Very interesting approach that works for MVVM as far as I can understand! How would that work for MVI where the whole screen state is held in only one observable?! (there is no separate isLoading property in the ViewModel)

    • @ydanneg
      @ydanneg 2 หลายเดือนก่อน

      then you do the same for the state flow

  • @FyUajYpUlM39
    @FyUajYpUlM39 2 หลายเดือนก่อน +1

    4:02 this disadvantage can be fixed by setting proper key parameters

    • @PhilippLackner
      @PhilippLackner  2 หลายเดือนก่อน

      @@FyUajYpUlM39 no matter what key you choose, it will be called again after a config change

  • @baljeetsandhu8718
    @baljeetsandhu8718 3 หลายเดือนก่อน +1

    Philipp there is another disadvantage of using init block, if you use states to manage your composable, and you have a lazyColoum which uses the data from states. you will see a lag on opening of the screen. Given that your api return data within 1 to 2 sec. Even using loading state won't remove that split second lag.

    • @KamrynB
      @KamrynB 3 หลายเดือนก่อน

      There isn't any lag if you initialize the UI state with the loading state from the start

  • @pavlosoia
    @pavlosoia 3 หลายเดือนก่อน +4

    how to trigger loading data if we pass arguments throught the navigation and need, for example, id to load data?

    • @tvhome2334
      @tvhome2334 3 หลายเดือนก่อน

      Launched effect

    • @JulienCorazzaRSS
      @JulienCorazzaRSS 3 หลายเดือนก่อน

      @@tvhome2334 You can also use the fact that viewModels have "keys". YOu can use this key to pass simple data like an ID or a name

    • @sergeykharuk5614
      @sergeykharuk5614 3 หลายเดือนก่อน +5

      via SavedStateHandle that we can retrieve in ViewModel constructor

    • @osisuper98
      @osisuper98 3 หลายเดือนก่อน

      @@sergeykharuk5614What if we use navigation savedStateHandle (the one that is not cached into the vm’s SavedState)?

    • @Flea997
      @Flea997 3 หลายเดือนก่อน

      really makes you think that every answer has a different opinion

  • @deepakbisht4957
    @deepakbisht4957 2 หลายเดือนก่อน

    This approach was discussed years ago in android developers youtube channel in very first video related to flow, stateflow and shared flow...

  • @motoharujap
    @motoharujap 11 วันที่ผ่านมา

    Sadly there are cases when you need to pass some value to the loading function, like an ID of an item to load. I stick to the approach with UI state objects that are emited by a flow which contain Loading flag, depending on which I ask for data from the composable.

  • @mackomako
    @mackomako 3 หลายเดือนก่อน

    Good to see something what I use for a while

  • @nikospsarakis5681
    @nikospsarakis5681 3 หลายเดือนก่อน +1

    Doesn't this means that if the app goes in the background for more than x seconds the state will be lost ? This approach may cover a configuration change due to rotation but fails other scenarios where an init block does not.

  • @raulprior9635
    @raulprior9635 24 วันที่ผ่านมา

    I'm kind of nooby in Test, with this approach how can I write a unitary test for my view model, I try it but even if I use test from turbine that for my understanding that should work as observer, I don't get my loading state updates properly. Note in the real implementation my app update states correctly.

  • @julianvasquezperez6799
    @julianvasquezperez6799 3 หลายเดือนก่อน

    What can I say? This approach is quite better than others (For these cases where you have an initial loading screen), I disagree with something about the main Android documentation (mentioned in the Medium blog), it doesn't mention that the best approach is the init block code, actually, I have been reading up in the architecture labs and they explicitly say that is bad practice to fetch the data in the init block specially by side effects and unit test behaviour (as you mentioned in the video).

  • @wilianc.b.3065
    @wilianc.b.3065 3 หลายเดือนก่อน

    Thanks for the video!! One question please: If I have a sole UI state variable in my view model and want to keep it like that, how do I use the flow in the view model? I do not want to provide a 2nd variable from the view model to the jetpack compose screen.

  • @sevarbg83
    @sevarbg83 3 หลายเดือนก่อน +4

    Google, take notes how one complicated topic is supposed to be explained.

  • @Oer_official
    @Oer_official 2 หลายเดือนก่อน

    thank you so much philipp i appleid this but i fall with one problem seeks for it's solution , see i had been using launcheffect in my app and then i swithch to init , i face a probelm : when i use navigations viewmodel also get killed causing every time realoading of initial data , i can resloved it by just hosting the viewmodel to teh navigation but it is a little big app doing so for evry screen is good ??

  • @aloussase
    @aloussase 3 หลายเดือนก่อน

    Hi Phillipp, what is the font you are using?

  • @nuralijakipov3585
    @nuralijakipov3585 หลายเดือนก่อน

    How can we use this approach with mvi pattern

  • @PrashantKumar-y6k
    @PrashantKumar-y6k 3 หลายเดือนก่อน

    How will I load data I have to take some arguments received in fragment, like a lookupUri, and I need to fetch data in the viewmodel using the lookupUri?

  • @058mohddanish4
    @058mohddanish4 2 หลายเดือนก่อน

    Hey what if I want to pass an argument on loadData(pageId:String), as pageId is a argument from previous page

  • @polarisnation201
    @polarisnation201 3 หลายเดือนก่อน

    This is what I wanted it. Thank you

  • @rizwansworld
    @rizwansworld 3 หลายเดือนก่อน

    Well explained. Thanks man.

  • @Nrodrigues90
    @Nrodrigues90 3 หลายเดือนก่อน +4

    What do you think about this approach?
    private val uiState = MutableStateFlow(false)
    val _uiState by lazy {
    loadData()
    uiState
    }

    • @ilyastoletov
      @ilyastoletov 3 หลายเดือนก่อน

      Your StateFlow is going mutable to usage point (your composable) so this kills the core idea of backing field

    • @npacebg
      @npacebg 3 หลายเดือนก่อน +1

      @@ilyastoletov You could just expose it as StateFlow, `val _uiState: StateFlow by lazy...`

    • @Nrodrigues90
      @Nrodrigues90 3 หลายเดือนก่อน

      ​@@ilyastoletov you should do it
      val _uiState: StateFlow ...

    • @vasiliychernov2123
      @vasiliychernov2123 2 หลายเดือนก่อน +1

      loadData() will be triggered when the property is accessed, not when flow collection is triggered, which may be not what you want.

  • @abhijeetsingh115
    @abhijeetsingh115 3 หลายเดือนก่อน

    I just have one doubt what if our use case methods is a suspend function. In cases it's not suspend it works but how to tackle suspension from onstart

  • @arthurgomes9248
    @arthurgomes9248 3 หลายเดือนก่อน

    Awesome content!

  • @babayaymen8893
    @babayaymen8893 3 หลายเดือนก่อน

    Philipp please make a video that explains the implemtation of sockJs with jetpack compose, it's urgent please

  • @HarshPatel-ky5vk
    @HarshPatel-ky5vk 3 หลายเดือนก่อน

    Hey @Philipp You are doing great work for so many developers.
    Please do let me know if you have created a video or a blog for a sample app includes MVVM+KOIN+KTOR Basically all kotlin only stuffs. if yes please share that or if not can you please make a video or a blog on that will be so helpful.

  • @kos534
    @kos534 หลายเดือนก่อน

    hi phillipp, what do you think about putting this in compose:
    var isFirstInitialized by rememberSaveable {
    mutableStateOf(false)
    }
    if (isFirstInitialized.not()) {
    viewModel.loadData()
    isFirstInitialized = true
    }
    it will only be called one time, it wont be called when configuration changed.

  • @eduardoruesta5180
    @eduardoruesta5180 3 หลายเดือนก่อน

    Niceee video!! love it! one question which should be the initialValue if for example the state is a list of Person? And this works for a Compose Multiplatform project? i've been initialazie data in the init block

  • @TheFlexath
    @TheFlexath 3 หลายเดือนก่อน

    Thanks Philipp and Article owner

  • @funnitish3909
    @funnitish3909 3 หลายเดือนก่อน

    Sir can you make a video on firebase storage integration on kmp desktop application

  • @ritikmalhotra6252
    @ritikmalhotra6252 3 หลายเดือนก่อน

    Can anyone tell me how to store the data of edit text inside a recycler view with flows as if i connect the edit text directly to the state flow then , app will be in a feedback loop and i wont be able to update the edit text

  • @everythingjdm8057
    @everythingjdm8057 3 หลายเดือนก่อน +4

    i don't know about others, but when i leave an app and come back, i would like to see it just like i left it caching could fix that, but i don't think it's worth the complexity so i will be sticking to the init block for now

    • @GakisStylianos
      @GakisStylianos 3 หลายเดือนก่อน

      You can get this with approach #3 as well if you store the last emitted value and at the time when you get a new observer you check if the last emitted value was data already. If yes you can just not do anything in your flow block, and just let the StateFlow show the last emitted value as-is.
      All this while still getting the benefits of that approach that init and LaunchedEffect do not give you.

  • @OrlanDroyd
    @OrlanDroyd 3 หลายเดือนก่อน +3

    Perfect timing I was just reading this article by Antonio Leiva 🔥
    Thanks for the clear explanation 💪

  • @John-qt6qk
    @John-qt6qk 3 หลายเดือนก่อน

    thanks a lot it was really helpful

  • @МойГосподин-ц1б
    @МойГосподин-ц1б 3 หลายเดือนก่อน +3

    LaunchedEffect is the most flexible and clean approach. Problems occur only when your presentation layer is not suitable for that. Consider UDF approaches like MVI, MVVM+UDF, ELM, TEA, Redux... State of your screen will let you know if an operation should be executed.
    If you use MVVM+UDF then check state in a guard statement before loadData().
    If you use MVI then it is reduer's responsibility to check if data should be loaded.
    Even in pure MVVM you can use isLoading LiveData in a guard statement at the beginning of loadData()

    • @МойГосподин-ц1б
      @МойГосподин-ц1б 3 หลายเดือนก่อน

      Well, even using pure MVVM you can use isLoading LiveData as a guard statement and LaunchedEffect is good for you

    • @roshanfx369
      @roshanfx369 3 หลายเดือนก่อน

      Do you have any article or repo i can refer to related to UDF approaches?

    • @МойГосподин-ц1б
      @МойГосподин-ц1б 3 หลายเดือนก่อน +1

      "Comparing ready-made solutions for implementing the MVI architecture on Android" by Abuzar on medium - Introduction to MVI and UDF in general (plus a list of popular MVI libraries)

    • @МойГосподин-ц1б
      @МойГосподин-ц1б 3 หลายเดือนก่อน +1

      "David González - Unidirectional Data Flow with..." on youtube - Nice talk about UDF implementation
      "Михаил Левченко - Итак, вы выбрали UDF-архитектуру. Как моделировать стейт?" on youtube - Great talk about UDF and state design, If you speak russian

    • @МойГосподин-ц1б
      @МойГосподин-ц1б 3 หลายเดือนก่อน +1

      "Algebraic Data Types (ADT) in Scala" by Daniel Ciocîrlan - To design good screen state I also recommend to learn about algebraic data types. The article is for Scala but works with Kotlin sealed classes as well
      Also consider drawing state machines for your screen to design screen state well

  • @ravshanbaxranov
    @ravshanbaxranov 2 วันที่ผ่านมา

    I think it takes advantages of first and second ways

  • @smithshaw1151
    @smithshaw1151 3 หลายเดือนก่อน +1

    The deeper I try to get into Android development, the more complicated it seems to get. Not a pleasant experience!

  • @panhakeat1004
    @panhakeat1004 3 หลายเดือนก่อน

    Can you make the video telling about Data Source

  • @kennynek
    @kennynek 3 หลายเดือนก่อน +6

    I do not like the WhileSubscribed approach. Do you also refresh your data after user staying on the screen for more than 5s, I do not think so, unnecessary complexity introduced. I would stick with Lazily. Also, do you need that @Before annotation for the purpose you mentioned? @Test annotaction doc says: The Test annotation tells JUnit that the public void method to which it is attached can be run as a test case. To run the method, JUnit first constructs a fresh instance of the class then invokes the annotated method. I think it is meant for external resources.

    • @aungkhanthtoo7678
      @aungkhanthtoo7678 3 หลายเดือนก่อน

      You need to add check whether data is already present in ui state object before calling loadData in onStart().

    • @sharkaboi
      @sharkaboi 3 หลายเดือนก่อน

      Guessing Phillip meant @BeforeClass rather, still don't see the point yeah

  • @akbarputra8726
    @akbarputra8726 3 หลายเดือนก่อน

    How if our inisial data required context to received it ? (I am not using DI)

    • @amalhanaja
      @amalhanaja 3 หลายเดือนก่อน +1

      the simplest solution, you can create a singleton to hold an application context reference and consume it

    • @sharkaboi
      @sharkaboi 3 หลายเดือนก่อน

      Another approach would be to use AndroidViewModel that gives the application instance

  • @fabianrojas2636
    @fabianrojas2636 3 หลายเดือนก่อน

    good video, but i still rather the ViewModel init approach, well it is normal to pass the repositories as parameters in the ViewModel constructor, just doing this the tests troubles are solved, well you just mock the repositories methods and attributes and when create the ViewModel in the test you pass the mocked repository

    • @PhilippLackner
      @PhilippLackner  3 หลายเดือนก่อน +1

      Your test troubles aren't solved just by passing a repo. The mocked repo will still load data when the VM is initialized

  • @AbdulelahAGR
    @AbdulelahAGR 3 หลายเดือนก่อน +7

    Good method, but I would not say the only correct way. Different use cases require different solutions.

    • @GakisStylianos
      @GakisStylianos 3 หลายเดือนก่อน

      Well, he clearly showed why you don't want to do the other approaches. What use case do you have where the final approach doesn't suit your needs?

    • @AbdulelahAGR
      @AbdulelahAGR 3 หลายเดือนก่อน +2

      ​ @GakisStylianos What he mentioned are the well-known and existing approaches. So yeah, what he mentioned is the best existing way for those who write tests.
      One can create their own approach. While such things take time to design and implement, sometimes your use case forces you to.
      And Phillipp already mentioned a use case where this approach will not suit you. It is if you do not want the screen to reload when user goes away from the app and comes back. Some API calls are expensive.
      I know you can do database caching to solve this. But now we are complicating it. If we go as simple as caching in a variable in the ViewModel itself, then we force caching in tests that might not be desired.

  • @GRajKumar-y2b
    @GRajKumar-y2b 3 หลายเดือนก่อน

    Wonderful 👍👍❤

  • @uop6238
    @uop6238 3 หลายเดือนก่อน

    I will stateIn the list in viewmodel, and map the flow with a sealed wrapper then emit loading status when onstart. Do not maintain a read-write flow like this in viewmodel.

    • @GakisStylianos
      @GakisStylianos 3 หลายเดือนก่อน

      You don't necessarily want to set the state to loading if you've already had data emitted before and you don't want to refresh that. You may want to just show the old data as-is without flickering a "loading" state in-between. Especially if fetching the data again is almost instant by grabbing it from a cache or a database for example

  • @-C-NguyenHuynhNhuThien
    @-C-NguyenHuynhNhuThien 3 หลายเดือนก่อน

    Many thanks!!!

  • @smnsrl
    @smnsrl 3 หลายเดือนก่อน

    What if you don't need to collect the result. Like an analytic call. If nothing collects the result, the initiation will never happen.

    • @PhilippLackner
      @PhilippLackner  3 หลายเดือนก่อน

      It's enough that there's anything that's collected, doesn't have to be related to the result

    • @smnsrl
      @smnsrl 3 หลายเดือนก่อน

      @@PhilippLackner yeah but response of the analytic request usually doesn't need to be collected. it doesn't even need to produce a flow.

  • @MostafaMohamed-st1uj
    @MostafaMohamed-st1uj 3 หลายเดือนก่อน

    Thank you so much

  • @LethalFellowship
    @LethalFellowship หลายเดือนก่อน

    Adding some random timeout of 5000 ms is a highway to flaky tests. Also, duplicating initial value is weird.

    • @PhilippLackner
      @PhilippLackner  หลายเดือนก่อน

      This timeout value is not random, it's very established on Android and you'll also find it in the Google docs. It's chosen because of ANRs on Android which happen when the UI isn't responding for > 5s. Please share an example where this leads to flaky tests

    • @LethalFellowship
      @LethalFellowship หลายเดือนก่อน

      @@PhilippLackner The fact it is mentioned somewhere in docs doesn't make it less of a magic number when hardcoded like this. As a Qt and KDE developer I've seen way too many flaky tests on CI, mainly due to waiting on non-deterministic events or some random timeouts like this one here; I'd imagine Android is no different. Less likely but still possible: if your busy CI server gets interrupted for whatever process scheduler reasons for more than five seconds, it could also fail. So what you said this third approach is better for tests sounds upside-down to me, I'm sorry.

  • @stefanusayudha1853
    @stefanusayudha1853 3 หลายเดือนก่อน

    but what if the load data requires an argument?

  • @ydanneg
    @ydanneg 2 หลายเดือนก่อน

    interesting.. thanks

  • @kimiaandroid
    @kimiaandroid 3 หลายเดือนก่อน +2

    this is why i love android, every approach is WRONG

  • @aminsakha155
    @aminsakha155 3 หลายเดือนก่อน

    Overall, such a 5-second delay may cause performance issues during the time.

  • @BaBaKRaufi
    @BaBaKRaufi 3 หลายเดือนก่อน +1

    How to call the loadData method with passing parameter?

    • @abr464
      @abr464 3 หลายเดือนก่อน +5

      If the parameter comes from user interaction, then you don’t need to initiate the data when the viewmodel is created. If the parameter comes from a previous screen as navigation arguments, then use SavedStateHandle in the viewmodel

  • @ArthurKhazbs
    @ArthurKhazbs 3 หลายเดือนก่อน

    Oh yes. Philipp really knows what we need as Android developers. You are a hero in our digital age!

  • @pantelischas9460
    @pantelischas9460 3 หลายเดือนก่อน

    Init block is not the best way, it will make more difficult the unit tests, and you can not control things,
    the loadData() is called the same time you create the ViewModel, if something is happening/changing at the same time the loadData() is called you can not control it,
    makes the unit test difficult

  • @lucasspasquier
    @lucasspasquier 3 หลายเดือนก่อน

    Perfect

  • @chiyembekezomaunjiri3278
    @chiyembekezomaunjiri3278 3 หลายเดือนก่อน

    @philipp is king

  • @pablovaldes6022
    @pablovaldes6022 3 หลายเดือนก่อน

    Nah thanks but no. I code my own state machine, this technique predates compose and is very effective.
    Initial state = "Created'. When the first onStart event arrives, my state machine switches from "Created" to "Started" state and executes a transition function.
    The subsequent OnStart events do not trigger the previous transition function but another function called refresh. "Started" state remains the same state, no state transition.

  • @shohjahonsirojev5974
    @shohjahonsirojev5974 3 หลายเดือนก่อน

    :like

  • @orek7327
    @orek7327 3 หลายเดือนก่อน

    Thisssssssss

  • @maxveres175
    @maxveres175 3 หลายเดือนก่อน

    In my view, your code should be readable and straightforward. The Google's approach doesn't meet my requirements, I wouldn't recommend it