JetBrains / compose-multiplatform

Compose Multiplatform, a modern UI framework for Kotlin that makes building performant and beautiful user interfaces easy and enjoyable.
https://jetbrains.com/lp/compose-multiplatform
Apache License 2.0
16.24k stars 1.18k forks source link

Desktop: User-friendly crash of the window when exception is thrown inside Composable (show alert to the user) #663

Closed igordmn closed 2 years ago

igordmn commented 3 years ago

Currently if we have a java exception inside Composable function we stop the rendering loop. And user just sees the frozen window (but with ability to close it).

Usually this kind of exception is a bug that should be fixed by the developer (IO exceptions shouldn't be thrown in Composable).

Possible solutions:

  1. close the window
  2. close the application
  3. show alert dialog (like in .NET applications)
  4. show alert dialog and close the window (or application)
  5. do nothing (like in the current implementation), provide a way to show a dialog on the any exception inside the rendering loop (currently developer can catch all exceptions in Thread.setDefaultUncaughtExceptionHandler)
lucas-ap150 commented 3 years ago

Could it be so that the window doesn't "freeze", or at least have an api to restart its event loop?

Right now if a ui exception happens, you are forced to close that window, there's no way to keep the app running on it. You could have an app architecture where app state is still in memory, and you wanted to simply recompose the ui again after an exception (maybe to a previous state so it doesn't crash again), and show an error indicator like intellij-idea does.

But since the window freezes for good, in my app i had to hack a solution where the DefaultUncaughtExceptionHandler quickly closes the old window and opens a new one, "resuming" the app there. But it doesn't look good ui-wise (window closing-opening out of nowhere, since an exception is unexpected), and i need to manually copy the old-window's position/size/etc to the new one. It would be nicer to simply recompose in the original window instead.

I came from javafx, where an exception in ui thread simply triggers a dialog, but the event loop stays running. You can suppress the dialog and handle the exception in other ways inside your app.

lucas-ap150 commented 3 years ago

Also i want to note that you can't close the frozen window if it is undecorated, since the manually drawn window controls are in compose code (Alt-f4 still works though)

igordmn commented 2 years ago

Now (1.0.0-rc3) we show a dialog on error by default, and close the window.

Users can override it via ComposeWindow.exceptionHandler or LocalWindowExceptionHandlerFactory

igordmn commented 2 years ago

There is a bug in 1.0.1. Because of it we can't override LocalWindowExceptionHandlerFactory. Will be fixed in 1.0.2/1.1.

Until then, the alternative is to set it via ComposeWindow:

    Window(onCloseRequest = ::exitApplication) {
        DisposableEffect(Unit) {
            window.exceptionHandler = WindowExceptionHandler {

            }
            onDispose {  }
        }
    }
zoff99 commented 8 months ago

can you show an example how to keep the app running after catching an exception like this? i can't get it to work. a compose exception always freezes the app. no way of recovery.

hakanai commented 7 months ago

Overriding LocalWindowExceptionHandlerFactory doesn't appear to work in the current stable release either. Debugger says my replacement exception handler is never called.

The existing ticket for it seemed to be #1764.

Setting ComposeWindow.exceptionHandler does work. That's clunky - I wanted something I could bury into a BetterErrorHandling composable which would work wherever you added it - but at least it gives us a working option.

It also leads me to wonder why setting the factory doesn't work... is it the case that it only works if you set it before displaying any windows? 🤔

My non-working example code

okushnikov commented 2 months ago

Please check the following ticket on YouTrack for follow-ups to this issue. GitHub issues will be closed in the coming weeks.