Top 3 Coroutine Cancellation Traps That Lead to Errors In Your Android App (Kotlin)

Поділитися
Вставка
  • Опубліковано 3 жов 2024

КОМЕНТАРІ • 50

  • @yurowitz
    @yurowitz 10 місяців тому +17

    This is the first time I hear about NonCancellable context even though I've been working with coroutines for about 2 years! This sure comes in handy in large-scale apps, thank you :)

  • @karolkulbaka8577
    @karolkulbaka8577 10 місяців тому +9

    cancelled coroutine work till first suspension point - that's a key note

  • @alexanderbernat182
    @alexanderbernat182 10 місяців тому +3

    NonCancellable context also is very useful in case when we have to save something and close the screen at the same time.

  • @nerrydanna
    @nerrydanna 10 місяців тому +1

    The last mistake is so tricky!! Thank you for the simple explanation.

  • @Narazgul
    @Narazgul 10 місяців тому +2

    Bin ja eh ein riesen Fan von deinem Kanal und deine Canvas und Testing Kurse haben mir richtig gut gefallen. Auch dieses Video hat mir wieder weitergeholfen und kam on-Point. Nachdem deine Zielgruppe ja vom Anfänger bis zum ambitionierten fortgeschritten Entwickler ist, würde ich mich auch sehr über Videos zum Thema Performance Analyse und Verbesserung, ebenso wie Memory Management freuen.
    Übrigens deine Idee eines neuen Kotlin Types der einen private setter und public getter built-in hat (aufgeschnappt in einem Podcast mit deiner Beteiligung) hab ich mir auch schon länger gewünscht. So spart man sich einfach diese ewige Redundanz im ViewModel 👍

    • @coalacorey
      @coalacorey 10 місяців тому +1

      Sehe ich auch so!

  • @kacetal
    @kacetal 10 місяців тому +3

    Hi Philipp, Could you make a video about coroutine backpressure. And how we could slow down the producer if the consumer cannot process all events. In RxJava this was easy thanks to the "request" method in Subscription, but in Flow it is not clear how this connection can be organized.

  • @arielapp9469
    @arielapp9469 10 місяців тому +5

    great video.
    for mistake #1: could you add a catch block before the generic exception for a specific Cancellation Exception?

    • @PhilippLackner
      @PhilippLackner  10 місяців тому +1

      If you rethrow it in that case yes

    • @arielapp9469
      @arielapp9469 10 місяців тому

      @@PhilippLackner
      try {
      } catch(e: CancellationException) {
      } catch (e: Exception) {
      }
      like that.

  • @safionweb
    @safionweb 10 місяців тому

    I wasn't aware of any of these mistakes. Thanks for such an amaizng content.

  • @gauravkumar-bs3pf
    @gauravkumar-bs3pf 5 місяців тому +1

    Please make a video on "Whatsapp Cloud API" integration in Jetpack Compose?

  • @guai9632
    @guai9632 2 місяці тому

    before rethrowing CE you better check if the coroutine isActive. you might get CE not from cancellation process, which is probably a bug somewhere down the callstack but you'll just rethrow it, and it'll silently kill your parent coroutine

  • @tomasglazr2466
    @tomasglazr2466 10 місяців тому +6

    In the #2 mistake: shouldn't the api.saveNote() call be also in the withContext block? What if the api call finishes and right away the coroutine is cancelled before it reaches the NonCancellable block?

    • @PhilippLackner
      @PhilippLackner  10 місяців тому +1

      The coroutine has no chance to check for cancelation there. That only works inside suspend functions

    • @tomasglazr2466
      @tomasglazr2466 10 місяців тому

      @@PhilippLackner oh right. Forgot about that part, where it has to be suspended 😅 thank you very much!

  • @ikerluqup5661
    @ikerluqup5661 2 місяці тому

    thanks

  • @manshalkhatri9289
    @manshalkhatri9289 10 місяців тому

    Great explaination Phillip

  • @shivumantur366
    @shivumantur366 10 місяців тому

    Nice explanation. Thank you Philipp. I am a big fan of you..❤

  • @mesutemrecelenk5447
    @mesutemrecelenk5447 10 місяців тому

    Again delightful traps 🎉 thanks phlipp 🎉🎉

  • @zeredantech2966
    @zeredantech2966 2 місяці тому

    Also at a trap 3 i guess, we could let the file be readed completely, but right after reading make ensureActive(), but because of we need to return it from lambda we can do something like: it.readBytes().apply{ensureActive()}. Then after reading file if we cancelled the coroutine it will not go further because of thrown CancellationException, which will propagade up to the launch coroutine

    • @PhilippLackner
      @PhilippLackner  2 місяці тому

      @@zeredantech2966 but then you break cancelation again 😅

    • @zeredantech2966
      @zeredantech2966 2 місяці тому

      @@PhilippLackner Maybe i found a solution, which will 1) not require decomposition of non-suspend time-demanding function. 2) Will not break Cooperative cancellation and Structured Concurrency.
      Of course, we cannot cancel such a function, because cancellation is just an Exception which is being raised by delay() for example. But, what if we call this function in the independant CoroutineScope Job, and join() it in our main Job? Then, it obviously will not stop and go on with reading file, BUT our coroutine will stop, because the join() function has it's own suspension and will raise own CancellationException when cancel(). If summarize, our non-suspend time-consuming function will work in a "hidden scope", which doesn't take part in the "Coroutine Tree", and in our Job we just launch it in this scope and join().
      Then, if not cancelled - then all ok, this function will finish work, then our join() will stop waiting and Job will be Completed.
      If cancelled, it firstly will cancel all it's children, so there is all ok, but then in will cancel itself and become again Completed. So, parent coroutine will be notified about cancellation.
      And if we wish return something, then just replace join() and launch() with await() and async().
      Thanks for reading a lot xD

  • @tuhinbhowmick8424
    @tuhinbhowmick8424 10 місяців тому

    Last one was something different....😮😮

  • @rohitjakhar6672
    @rohitjakhar6672 10 місяців тому

    We can move ensureActive() inside if condition too.

  • @mateusbauer7299
    @mateusbauer7299 10 місяців тому

    Great, thanks.

  • @MisterBPK
    @MisterBPK 10 місяців тому

    really helpful 😊

  • @GoodSmile3
    @GoodSmile3 10 місяців тому

    Learned the first one the hard way

  • @asimbrsah
    @asimbrsah 10 місяців тому

    Useful

  • @stefanusayudha1853
    @stefanusayudha1853 8 місяців тому

    what about using Result?
    as what i know, this practice is not recommended.. hidden controll flow

  • @marksheekey520
    @marksheekey520 10 місяців тому +1

    In the furst example could you not return a boolean to indicate success, in the catch block return false and after the "upload" return true.

    • @bitwisedevs469
      @bitwisedevs469 10 місяців тому +1

      That is not applicable if you are using someone's library or API in which you are not in control of what to return.

  • @keepgoingman5829
    @keepgoingman5829 10 місяців тому

    The Coroutine cancellableException is very troublesome and tricky :(
    The thing is that coroutines will be "really" cancelled when they meet other suspension point after cancelling.

  • @albertbo2178
    @albertbo2178 10 місяців тому

    1rst mistake could also be avoided saying that the error in the catch error is not Exception and is specifically a custom one?

  • @acker.01
    @acker.01 10 місяців тому

    Please make a complete android development course for beginners

  • @Sandy-dz6qz
    @Sandy-dz6qz 10 місяців тому

    I have a doubt in Note example, when saving Note (isSynched=false) then Api call and then by using Upsert function (isSynched = true) you updated same note.. but after first insert Note is added to database with autoincrememted id, how you update same note without updating id in note object?

    • @bitwisedevs469
      @bitwisedevs469 10 місяців тому +1

      Because that is just a sample, the main focus of the topic is not about Room and how to update data instead it focuses on how to handle cancellation scenario properly in Coroutine. What is being show is like a pseudo code for you to have clearer idea of the scenario.

    • @Sandy-dz6qz
      @Sandy-dz6qz 10 місяців тому

      @@bitwisedevs469 Ohh.. ohk.. I always have to work with Room database in my company.. So that's why I was curious if there is shortcut to update database using UPSERT function. Thanks for info

    • @santoshbhatt6924
      @santoshbhatt6924 10 місяців тому

      ​@@Sandy-dz6qz Hi, Actually I have a doubt, in one of the scenario I was using insert annotation to insert the newly entered notes and I had set id to auto increment and if the id is already present then it should ignore that as i had used onconflict strategy replace. But it is always inserting new row no matter it is already present or not. Do you have any idea why it is happening?

    • @Sandy-dz6qz
      @Sandy-dz6qz 10 місяців тому

      @@santoshbhatt6924 When inserting Notes into database you have to get Id of that perticular row first and need to set that id to Notes object and then fire a query with same id.. then onconflict strategy will work

    • @fightmisinfo
      @fightmisinfo 10 місяців тому

      The id is not auto-incrementing in his example.

  • @5erTurbo
    @5erTurbo 10 місяців тому

    Trying to make app "safe" and not embracing the exceptions leads to all kinds of bugs

  • @Mohit-il9gx
    @Mohit-il9gx 10 місяців тому

    Do you work in an company / organisation or freelance?