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

แชร์
ฝัง
  • เผยแพร่เมื่อ 24 ธ.ค. 2024

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

  • @yurowitz
    @yurowitz ปีที่แล้ว +18

    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 ปีที่แล้ว +9

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

  • @kacetal
    @kacetal ปีที่แล้ว +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.

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

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

  • @Narazgul
    @Narazgul ปีที่แล้ว +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 ปีที่แล้ว +1

      Sehe ich auch so!

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

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

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

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

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

      If you rethrow it in that case yes

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

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

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

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

  • @tomasglazr2466
    @tomasglazr2466 ปีที่แล้ว +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  ปีที่แล้ว +1

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

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

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

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

    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  4 หลายเดือนก่อน

      @@zeredantech2966 but then you break cancelation again 😅

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

      @@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

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

    Those code seems messy 8:23, any handy extensions to handle canceled exceptions?

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

    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

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

    Great explaination Phillip

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

    We can move ensureActive() inside if condition too.

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

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

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

    thanks

  • @marksheekey520
    @marksheekey520 ปีที่แล้ว +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 ปีที่แล้ว +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.

  • @gauravkumar-bs3pf
    @gauravkumar-bs3pf 8 หลายเดือนก่อน +1

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

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

    Great, thanks.

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

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

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

    Again delightful traps 🎉 thanks phlipp 🎉🎉

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

    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.

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

    Last one was something different....😮😮

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

    Learned the first one the hard way

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

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

  • @Sandy-dz6qz
    @Sandy-dz6qz ปีที่แล้ว

    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 ปีที่แล้ว +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 ปีที่แล้ว

      @@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 ปีที่แล้ว

      ​@@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 ปีที่แล้ว

      @@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 ปีที่แล้ว

      The id is not auto-incrementing in his example.

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

    really helpful 😊

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

    Useful

  • @Mohit-il9gx
    @Mohit-il9gx ปีที่แล้ว

    Do you work in an company / organisation or freelance?

  • @5erTurbo
    @5erTurbo ปีที่แล้ว

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

  • @acker.01
    @acker.01 ปีที่แล้ว

    Please make a complete android development course for beginners