5 Fatal Coroutine Mistakes Nobody Tells You About

แชร์
ฝัง
  • เผยแพร่เมื่อ 29 ก.ย. 2024

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

  • @marksunghunpark
    @marksunghunpark 2 ปีที่แล้ว +90

    It's parellel dispatch and you can even use it for async mapper. You can make the code shorter if you want:
    val firstNames = userIds.map { userId ->
    async { getFirstName(userId) }
    }.awaitAll()

    • @pradiptapriya7546
      @pradiptapriya7546 2 ปีที่แล้ว +5

      Hi, do you mind answering some of my questions regarding this async? When using async and awaitAll() to get data, is there a chance that the order of name lists retrieved will be changing every time the operation is done? Because I thought since it's being done parallel, there's a time when some data in API are obtained faster than others, making the order of the list changing every time based on how the network performance is right? Or the list will be always the same?

    • @marksunghunpark
      @marksunghunpark 2 ปีที่แล้ว +5

      @@pradiptapriya7546 It's same with
      async { getFirstName(userIds[0]) } +
      async { getFirstName(userIds[1]) } +
      async { getFirstName(userIds[2]) }...
      So, it should be the same order.

    • @pradiptapriya7546
      @pradiptapriya7546 2 ปีที่แล้ว +1

      @@marksunghunpark I see! Thank you very much! With this, I can improve my code a bit!

    • @dev_jeongdaeri
      @dev_jeongdaeri 2 ปีที่แล้ว

      Async mapper 엄청나네요!! 감사합니다!!👍👍👍👍

    • @phantuananh2163
      @phantuananh2163 2 ปีที่แล้ว

      Dope 😍

  • @alexiitrotsenko3781
    @alexiitrotsenko3781 2 ปีที่แล้ว +1

    Hi @Philipp Lackner for the great video! However I believe, that there is "mistake" in mistake #3.
    Right now networkCall() is thread-safe since it's using delay(), which is non-blocking operation. Thus I will not block underlying thread/dispatcher.
    Perhaps If you would like to demo blocking IO call - you can use Thread.sleep(2000) instead.

  • @silvestreramirez4515
    @silvestreramirez4515 2 ปีที่แล้ว

    But for example if I have one thousand client IDs this works? Can I have one thousand async task at the same time running?

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

    Hmmm, that's a lot of gotchas for a beginner.

  • @SamRamezanli
    @SamRamezanli 2 ปีที่แล้ว +54

    I don't know how to express how helpful this video was.
    blogs and tutorials often tell us what to do, but it's important to understand what not to do as well.
    Looking forward to more videos like this

  • @codinginflow
    @codinginflow 2 ปีที่แล้ว +23

    This changes everything!

    • @RanbirSingh-dl9co
      @RanbirSingh-dl9co 2 ปีที่แล้ว

      Above dialogue is said by Bulma from Dragon ball Super when Goku arrive when frizza attacked earth.

  • @it-6411
    @it-6411 2 ปีที่แล้ว +35

    Pay attention, that when you use .awaitAll() function in the list of deferred items and if any of these will throw exception, you'll get exception for the whole operation. So, you should use .awaitAll() only in case, when you except full success of all async calls. In other case to handle exceptions for specific items, you can use list.map { it.await() } and try/catch block.

    • @PhilippLackner
      @PhilippLackner  2 ปีที่แล้ว +5

      Correct, thanks for mentioning :)

    • @it-6411
      @it-6411 2 ปีที่แล้ว

      @@PhilippLackner you’re welcome)

    • @abdremo
      @abdremo 2 ปีที่แล้ว

      OK🤙

    • @ChrisAthanas
      @ChrisAthanas 2 ปีที่แล้ว

      Like this?
      suspend fun getUserFirstNames(userIds: List): List {
      // Alternative solution - executed in parallel, but allows for each item to cause exception
      val firstNames4 =
      coroutineScope {
      userIds.map { userId ->
      async {
      try {
      getFirstNameWithExceptions(userId + 1000)
      } catch (e: Exception) {
      println("Exception in getUserFirstNames: $e")
      "Error for id=${userId+1000}: $e"
      }
      }.also {
      }
      }
      }.also {
      }.awaitAll()
      return firstNames4
      }
      suspend fun getFirstNameWithExceptions(userId: Int): String {
      delay(500)
      println("getFirstName: $userId")
      if (userId > 1005) { // simulate an error
      throw Exception("userId > 505")
      }
      return "John $userId"
      }
      // note: I am using the `.also{}` blocks in order to let the IDE show the type at that point in execution

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

      thank you for your correctly idea.

  • @yash1307
    @yash1307 2 ปีที่แล้ว +27

    Sir why are you not becoming a Google Developer Expert? Because you provide an amazing and helpful content...

    • @ssgojekblue
      @ssgojekblue 2 ปีที่แล้ว

      So true!

    • @protaties
      @protaties 2 ปีที่แล้ว

      *JetBrains Developer Expert

    • @royce-rich
      @royce-rich 2 ปีที่แล้ว +3

      Free google sales person = GDE

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

      that doesnt give money!

  • @pizzapizzadesu
    @pizzapizzadesu 2 ปีที่แล้ว +8

    great timing. i was just about to make the "mistake 1" one for retrieving images. Really appreciated

  • @LouisCognault
    @LouisCognault 2 ปีที่แล้ว +3

    Your solution to mistake #2 still has a mistake: If cancellation happens while delay is suspended, job will never be cancelled.

  • @-Kimma-
    @-Kimma- 2 ปีที่แล้ว +5

    This is so good and clear!
    This also explains some minor issues I have to understand some of the functionality with coroutines.
    I'm going to use this video as code snippets when coding my coroutines 😀

  • @ayushs_2k4
    @ayushs_2k4 ปีที่แล้ว +1

    At 16:46, Shouldn't we use Dispatcher.IO

  • @thanosfisherman
    @thanosfisherman 2 ปีที่แล้ว +2

    Mistake 4. If you make this suspending function return coroutineScope ( The suspend function you also used for mistake 2) or even withContext. Then the cancellation exception will be actually propagated to the outer scopes even if you explicitly catch in inside riskyTask e.g suspend fun riskyTask() = withContext() {}

  • @ackerman6992
    @ackerman6992 2 ปีที่แล้ว +4

    Why it necessary to call async function inside coroutine scope? 🤔 We can call a suspend function in other suspend function right? Or we call coroutine scope so that the function inside coroutine scope works independently?

    • @skullkrum20
      @skullkrum20 2 ปีที่แล้ว

      Usually your coroutines code runs sequentially. We use async so that we can immediately loop and call async again for the new iteration. This way you start all jobs initially and then wait for all of them to finish with "awaitAll".

    • @ackerman6992
      @ackerman6992 2 ปีที่แล้ว

      @@skullkrum20 yes i undestood that, but i was asking why we need to call async inside coroutine scope.

    • @skullkrum20
      @skullkrum20 2 ปีที่แล้ว

      @@ackerman6992 Its for that reason. If you don't you will run everything sequentially. Usually you don't need to if you're fine with that.
      Good name btw, I'm in love by Shingeki no Kyogin. :D

    • @ackerman6992
      @ackerman6992 2 ปีที่แล้ว

      @@skullkrum20 ohk got it, Thanks 😂

    • @bjugdbjk
      @bjugdbjk 2 ปีที่แล้ว

      @@ackerman6992 coroutinescope, in this context , this is required because u r launching the coroutines with async, and to control them u need coroutinescope here !! And inside a suspend function we can't launch a coroutine !!

  • @ChrisAthanas
    @ChrisAthanas 2 ปีที่แล้ว

    @PhilippLackner @17:36 you mention needing to cancel the long-living CoroutineScope, but did you mean any Jobs that were started with the long-living CoroutineScope, and not cancelling the CoroutineScope itself? I dont see any way to cancel the CoroutineScope, just jobs associated with the scope. Please advise.

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

    And in example 1 there is an interesting moment: Since we use coroutineScope{}, we dont need to await all deffered elements, because, With the rules of "Structured Concurrency", the Deffered, which is being launched under the hood in coroutineScope{} will not be completed until all children get completed, so this call of coroutineScope will wait until all async{} will give us the result. After this, we can use non-suspend method getCompleted() to just collect values.

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

    Very helpful explanations!
    At 4:07, with what keystrokes did you move the whole for loop up together? Ah, looks like Shift+Cmd+Up on Mac. Very useful!
    (Unfortunately, the video title is misleading clickbait. These are not mistakes that "nobody tells you about." Making your suspend functions main-safe, for example, is a principle thoroughly discussed in Android documentation about coroutines.)
    On mistake #5, the point is valid that the lifecycleScope is too short-lived for the purpose of posting data to an API, and using the viewModelScope is an improvement. But the ViewModel too can be destroyed (for example if the user navigates to another activity) while data is being posted to the API, and that is not what the user wants either. Android docs recommend that "business-oriented operations," such as uploading users' data, should survive even process death. For that, WorkManager is recommended.

  • @aleksandr.liublinskii
    @aleksandr.liublinskii 5 หลายเดือนก่อน

    In mistake #1 since we have multiple coroutines spawned by async, and they all access the mutableListOf concurrently, shouldn’t we use thread safe data structure, for example COW list instead?

  • @HassanBadran-w4o
    @HassanBadran-w4o 4 หลายเดือนก่อน

    Hello, thanks for the amazing videos but one question always concerns me:
    isn't sometimes the overhead of creating a lot of coroutines defies the purpose of performing tasks in parallel? or wouldn't it be a problem?

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

    Great video. Rather than checking if an exception is a CancellationException in a try-catch block, you could use runCatching instead which does not catch CancellationExceptions

  • @LogicPhalanx
    @LogicPhalanx 2 ปีที่แล้ว +2

    Mistake 3 is actually main safe but I get your point. Delay doesn't block the calling thread.

  • @BM-tp4kn
    @BM-tp4kn 2 ปีที่แล้ว +3

    Google says Don't hardcode Dispatchers when creating new coroutines or calling withContext.
    inject Dispatchers
    This dependency injection pattern makes testing easier as you can replace those dispatchers in unit and instrumentation tests with a TestCoroutineDispatcher to make your tests more deterministic

  • @christianmeazza2309
    @christianmeazza2309 2 ปีที่แล้ว +1

    I'm glad you're here to tell me about those mistakes, you are the best. I see the next video coming: "5 Fatal Kotlin Flows Mistakes Nobody Tells You About" :D

  • @samandar7632
    @samandar7632 2 ปีที่แล้ว

    My Android Studio (Bumble bee); not implementing github dependencies! Who resolved this problem?

  • @GrahamFirst
    @GrahamFirst ปีที่แล้ว

    In mistake 3, shouldn't "networkCall" just return a string (or throw an exception)? I don't see the point of wrapping it in a Result in this case.

  • @KPACIBO_UA
    @KPACIBO_UA 2 ปีที่แล้ว

    I skipped start of the video and wondering what are all of those methods and I don't know them cuz I was thinkin that it is Java Script language xD

  • @7xFuryPlayz
    @7xFuryPlayz ปีที่แล้ว

    my question is ? will its good or bad to use repository class in the last mistake ? i think so viewModel should not interact with your api , repository class should interact with your api and give data to viewModel and then viewModel give data to activity or fragment ui right ???

  • @zeyadabdo1964
    @zeyadabdo1964 ปีที่แล้ว

    Do I need to call suspend functions of Retrofit and Room on a background thread?

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

    Can i update UI like async(first) method?

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

    as always with your videos, very interesting for self learners !

  • @otoS97
    @otoS97 2 ปีที่แล้ว +1

    Everyone is providing video ideas so I would say it too:
    Running android Junit and Android tests on Gitlab's CI on every commit.
    If you're had any experience with this it would be a great video.
    Maybe with docker maybe without it.

  • @ssgojekblue
    @ssgojekblue 2 ปีที่แล้ว +1

    I'm refactoring all my Mistake 5 now 😃

  • @dk6024
    @dk6024 2 ปีที่แล้ว +1

    In the first example, you could have mapped over the incoming IDs and avoided some code and mutability.

  • @asadnaqvi8901
    @asadnaqvi8901 2 ปีที่แล้ว +1

    The content you are providing is not available on highly paid sites. You are doing great work. Keep it up buddy 🎉🎉

  • @kemasdimas
    @kemasdimas 2 ปีที่แล้ว +2

    Wow thank you, didn't realize I made a lot of inefficient coroutine calls in my app! 😅 Does your paid course cover this extensively? Will need to check it out

    • @PhilippLackner
      @PhilippLackner  2 ปีที่แล้ว +1

      My paid courses cover lots of topics and best practices in a bigger practical project 😄

    • @kemasdimas
      @kemasdimas 2 ปีที่แล้ว

      @@PhilippLackner bought it, thanks!

  • @AdrianTache
    @AdrianTache 2 ปีที่แล้ว +1

    I think mistake 2 is misleading, because that code should be safe as written. But I agree, with components that aren't coroutine safe, like long running calculations, you should do a check before continuing them whenever it makes sense.

    • @johnf419
      @johnf419 2 ปีที่แล้ว

      Agreed, I think the example was not realistic

  • @bjugdbjk
    @bjugdbjk 2 ปีที่แล้ว +1

    Even without async just with the launch, we can have parallel execution because both are non-suspending calls !! Async is specifically useful when you want to get something out from a coroutine !!

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

    lol the mistake is failing to DDoS your server?

  • @alishanvaliani9952
    @alishanvaliani9952 2 ปีที่แล้ว

    Hi! Make video about Maps Compose, Please!

  • @MrGfpf
    @MrGfpf 2 ปีที่แล้ว

    Great tips! Thanks in advance! Brazil!

  • @mohammedsallam9841
    @mohammedsallam9841 2 ปีที่แล้ว

    So bad That I could not guess any of the mistakes

  • @emilienchampion4138
    @emilienchampion4138 2 ปีที่แล้ว +1

    rythmeur

  • @chibuezefelixanyanwu300
    @chibuezefelixanyanwu300 2 ปีที่แล้ว

    Can you please handle paginate data with retrofit

  • @donwald3436
    @donwald3436 2 ปีที่แล้ว

    So clients will make unbounded concurrent requests... you like getting DDOS?

  • @aherbel
    @aherbel 2 ปีที่แล้ว +1

    For Mistake #1, doesn't creating a new coroutineScope inside a suspend function loose the parent scope? I mean, if some error is thrown inside that coroutineScope, the parent will not get cancelled...

    • @bobbybeat1
      @bobbybeat1 2 ปีที่แล้ว

      The coroutineScope function creates a CoroutineScope that inherits the context of the parent and forwards cancellations/exceptions to the parent scope.
      More info: kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/coroutine-scope.html

  • @dev_jeongdaeri
    @dev_jeongdaeri 2 ปีที่แล้ว

    Thanks for super awesome tutorial!!👍👍👍👍❤️

  • @dev_jeongdaeri
    @dev_jeongdaeri 2 ปีที่แล้ว

    Thanks for super awesome tutorial!!👍👍👍👍❤️

  • @dev_jeongdaeri
    @dev_jeongdaeri 2 ปีที่แล้ว

    Thanks for super awesome tutorial!!👍👍👍👍❤️

  • @Lucien-ow5ne
    @Lucien-ow5ne 4 หลายเดือนก่อน

    Great video, thank you!

  • @jose-naves
    @jose-naves 2 ปีที่แล้ว +1

    Pure gold. Thanks a lot!

  • @TheSpjoe
    @TheSpjoe 2 ปีที่แล้ว

    IMHO mistake 4 should be about using CancelationExceptions in the first place. Making flow-control with a callstack dependent concept is already the mistake. Quite disappointed to learn that kotlin uses Exception to control the active state of its routines. I hoped they learned from the broken InterruptedException from java I just wonder why and how this can be overlooked when designing a new language.
    TL;DR mistake 4 the mistake is the CancelationException and not the people forget to handle this one Exception differently.

  • @grimonce
    @grimonce 2 ปีที่แล้ว

    There's something weird with the first example...
    isn't appending to the list synchronous in here?
    Why didn't we include it in the async block?
    I don't know the first thing about Kotlin, I use different tools, but to me this didn't fix anything, unless using "coroutineScope" makes appending asynchronous somehow...
    Also won't adding the firstNames to the async block become a race condition?
    Is the memory reserved for the result ahead of time thanks to the type DeferredString?

  • @MrBicelis
    @MrBicelis 2 ปีที่แล้ว

    What should I do if I want a suspend function in viewmodel (Room function to update entity) to finish the work even after viewmodel gets destroyed?

    • @PhilippLackner
      @PhilippLackner  2 ปีที่แล้ว +1

      Use an application scope instead of viewmodelscope

    • @MrBicelis
      @MrBicelis 2 ปีที่แล้ว

      @@PhilippLackner thanks, Phillip! You mean you would launch such a coroutine with GlobalScope? I thought it's a bad practice to use it, so I was looking for ways to avoid it. Even looking into using WorkManager... 🙂
      For more context: my activity is used for reordering and/or adding items to a list, after user presses back/up button, I want to update the list in a Room database. I was using viewModelScope, but it wouldn't manage to save in time before the viewmodel gets destroyed.
      Btw, amazing content Phillip!

  • @saquibsiddique2641
    @saquibsiddique2641 2 ปีที่แล้ว

    Really very helpful thanks for sharing @Philipp

  • @_checkit
    @_checkit 2 ปีที่แล้ว

    #5 so let's say that button is a "save and close" button for the current activity. What then?
    You pass the "finish()" method as callback to the viewmodel method?

  • @DanieleSegato
    @DanieleSegato 2 ปีที่แล้ว

    Randomly being suggested your video, decide to watch it.
    Well the 4th mistake, you are partially wrong there with your explanation: if you throw a cancellation exception in your code, yes, you would eat that up. But in most cases the cancellation exception you would be catching would be from a suspendable function, your delay in this case. And what would happen there is that the coroutines would have been calcelled, regardless of you catching the exception or not. BUT if you cancel the exception and then try to execute some more suspendable call after that it would fail. So your solution is correct, you should be doing that (checking for cancellation / avoid catching cancellation exception. But your explanation is not entirely correct.
    :-) hope I was helpful

  • @ramasubramanian3154
    @ramasubramanian3154 2 ปีที่แล้ว +1

    please make this a weekly video series.🙏

  • @crayolaksh
    @crayolaksh 2 ปีที่แล้ว

    Hi, mistake 2 can also be handled with a withTimeout block right? it'll throw an exception if the operation within takes longer than specified time. Please correct if I'm wrong

  • @Shasha-zs4dx
    @Shasha-zs4dx 2 ปีที่แล้ว

    Kudos to you for making this video...Learned very tricky points related to coroutines by watching this..Thank you mate.keep making these awesome videos

  • @amnsatija
    @amnsatija 2 ปีที่แล้ว

    best corotuines video ever

  • @psistarpsi80
    @psistarpsi80 2 ปีที่แล้ว

    I wish you'd make a video like this for Lua. Lua coroutines continuously befuddled me.

  • @antonychepel5797
    @antonychepel5797 2 ปีที่แล้ว

    Thanks for video! So usefull. What is that IDE? Visual Code or something else?

  • @TheKuoala
    @TheKuoala ปีที่แล้ว

    One thing worth mentioning for Mistake1 is the fact that coroutineScope will suspend until all the async calls finish. Therefore reading the result code like this could be confusing since you aren't really waiting for anything outside of the coroutineScope block.

  • @khanzadakashif8248
    @khanzadakashif8248 2 ปีที่แล้ว

    Am I the only one who's missing that mechanical keyboard sound??? xD

  • @zekininadresi
    @zekininadresi 2 ปีที่แล้ว

    I think using launch would be better as async would bring all parent the scope down if once job fails to retrieve the name (unless it's supervised).

  • @chandlerbing2820
    @chandlerbing2820 2 ปีที่แล้ว

    Love all your videos. Please do more Android studio projects. Thank you so much!!!!!!!

  • @zanyking
    @zanyking 2 ปีที่แล้ว

    Be careful while using async in web backend development, if the function is going to be triggered by client request, and you expect high QPS on this function, then you have to create your own thread pool for this async to use
    Never use default thread pool, because it’s small and might exhausted and cause other client requests await

  • @javlontursunov6527
    @javlontursunov6527 ปีที่แล้ว

    Is what you are saying applicable to Java as well ?

  • @path_ethics
    @path_ethics 2 ปีที่แล้ว

    How to create and manage cancelation of our own scope, for example in case we want to have a scope binded to our whole application?

  • @ДмитроЯковлєв-ч6ф
    @ДмитроЯковлєв-ч6ф 2 ปีที่แล้ว

    Can you please, make several hours of such kind examples) so amazing stuff

  • @RexTorres
    @RexTorres 2 ปีที่แล้ว

    Thanks for this awesome video. I learned A LOT. I use coroutines a lot so I will need to review those.

  • @adamjacob5482
    @adamjacob5482 2 ปีที่แล้ว

    Love your videos, love your work. Always great content! Thank you very much :)

  • @naughtguap3832
    @naughtguap3832 2 ปีที่แล้ว

    "Fatal" tho, lmao

  • @solo-ps9vb
    @solo-ps9vb 2 ปีที่แล้ว

    Very helpful. Using coroutines means coding in a new way.

  • @z-h-d
    @z-h-d 2 ปีที่แล้ว

    nice video to watch before sleep ) easy listening, very clear and positive 👍

  • @spitze3768
    @spitze3768 2 ปีที่แล้ว

    Great videos! They are very informative and have help me a lot in my shift to kotlin. Keep up to good work!

  • @a.rohimsama7222
    @a.rohimsama7222 8 หลายเดือนก่อน

    Thank you for sharing! super helpful! love it!

  • @sergeyplotnikov5031
    @sergeyplotnikov5031 2 ปีที่แล้ว

    Really useful content/ Thank you very much!!!

  • @jorgea.garzav4650
    @jorgea.garzav4650 2 ปีที่แล้ว

    (I'm not Kotlin fluent, actually, I know nothing about) when I first read "suspend fun", I got sad.

    • @ChrisAthanas
      @ChrisAthanas 2 ปีที่แล้ว

      its not as scary as it looks but also sometimes it is

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

    i'm addicted to your videos man, i can't sleep.

  • @dedeandres455
    @dedeandres455 2 ปีที่แล้ว

    amazing video and good explaination
    Thanks Philipp

  • @SudhanshuKumar-xy6xv
    @SudhanshuKumar-xy6xv 2 ปีที่แล้ว

    Extremely helpful please make more such videos

  • @rahul_spawar
    @rahul_spawar 2 ปีที่แล้ว

    This video is very helpful , please make more videos like this

  • @joaquinalanalvidrezsoto5054
    @joaquinalanalvidrezsoto5054 2 ปีที่แล้ว

    Sehr tolles Video. You should make more like this :D

  • @imashnake_7151
    @imashnake_7151 2 ปีที่แล้ว

    Wow you look so much healthier now, great work!

  • @abdullahejaz6571
    @abdullahejaz6571 2 ปีที่แล้ว +1

    is not retrofit call main safe?

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

    what an explanation Philip . You earned a like .

  • @amirhosseinghafoorian9985
    @amirhosseinghafoorian9985 2 ปีที่แล้ว

    nice issues were mentioned here , especially the defered one

  • @edwinkungu1155
    @edwinkungu1155 2 ปีที่แล้ว

    Waiting for the day you'll call it co-routine

  • @shutanovac
    @shutanovac 2 ปีที่แล้ว

    Your best video as far as I'm concerned 👍

  • @s-w
    @s-w 2 ปีที่แล้ว

    I see a Philipp Lackner video, I click.

  • @StreetsOfBoston
    @StreetsOfBoston 2 ปีที่แล้ว

    Nice video!
    But Mistake #3 is not a mistake at all:
    The function "networkCall" *suspends* for 3 seconds. It does not *block* for 3 seconds. Since "networkCall" is not blocking, there is no need to fix it by using a "withContext".
    If you wrote/coded "Thread.sleep(3000L)" instead, then this example would have been a real mistake, since you could have *blocked* (not suspended) the main thread.

    • @etiennebeaulac8148
      @etiennebeaulac8148 2 ปีที่แล้ว

      The issue is not that he thought it was blocking, but that the function was not main-safe, which is a mistake. Changing the context to Dispatchers.IO was the right thing to do. Of course, as he mentions, if you use Retrofit you don't need to worry about this since it does it for you.

    • @StreetsOfBoston
      @StreetsOfBoston 2 ปีที่แล้ว

      @@etiennebeaulac8148 If the "networkCall()"'s body contained "Thread.sleep(3000L)" (or has some actual blocking call like waiting for a socket), then switching the context to Dispatchers.IO would have made perfect sense
      Written as it is, the code in Mistake -#3, is entirely main safe, since there is no blocking code, only suspending code.
      Replacing 'delay' with 'Thread.sleep' will make it blocking and not main-safe.
      It's a bit of nit-picking, but I think details are important sometimes 🙂

  • @TiagoDvl
    @TiagoDvl 2 ปีที่แล้ว

    Really nice model of videos. Keep up, man.

  • @anupdey99
    @anupdey99 2 ปีที่แล้ว

    Excellent content as always! Please make a series about those mistakes. Appreciate your hard work. 🙌

  • @GeolseuDeiGamers
    @GeolseuDeiGamers 2 ปีที่แล้ว

    Thank you so much, your videos are awesome

  • @Monarch_943
    @Monarch_943 2 ปีที่แล้ว

    Damn this was a very good video! it seems I'v been making alot of mistakes :/

  • @thegreatwarrior4989
    @thegreatwarrior4989 2 ปีที่แล้ว

    Very informative vedio👍👍😉😉😉

  • @rustamibrahimli2113
    @rustamibrahimli2113 2 ปีที่แล้ว

    Can you tell me please: What is your Color theme?
    This is such a beautiful theme

    • @bjugdbjk
      @bjugdbjk 2 ปีที่แล้ว

      shld be Xcode-dark

  • @Nekrull
    @Nekrull 2 ปีที่แล้ว

    You're right that suspend functions should not be exposed to the UI and I'm with you 200%, but have you seen Google's paging library? that thing not only uses suspend functions to submit data to the adapters, but it also seems to run load queries on the UI by passing the paging source to the list's adapter, it's actually the only library that I promised that I will never use

    • @PhilippLackner
      @PhilippLackner  2 ปีที่แล้ว +1

      I don't like the paging library either, but the load queries are done in the viewmodel afaik

    • @Nekrull
      @Nekrull 2 ปีที่แล้ว

      @@PhilippLackner I will test it out but I don't think it does it on the view model, you post a paging source (which in effect is an object that contains suspending functions to load the data) to your paging adapter through the fragment or activity's lifecycle scope, so it's pretty much impossible to run something on viewmodelscope, though I guess you could create the adapter on viewmodel and let the observer attach it to the paged list, but adapters in the view model are a bitch to unit test without robolectric

  • @o.z.sidd.
    @o.z.sidd. ปีที่แล้ว

    ❤️❤️