Search code examples
codenameone

Codename One EasyThread.addGlobalErrorListener usage


I didn't understand exactly how to use addGlobalErrorListener(EasyThread.ErrorListener err).

Let's go to my code in the init():

        // Pro only feature (disabled)
        Log.bindCrashProtection(false);

        // Custom EDT error handling
        CN.addEdtErrorHandler(e -> {
            Log.p("\n\n--- EDT CRASH REPORT ---\n", Log.ERROR);
            Log.e((Throwable) e.getSource());
            Server.sendLogAsync();
            Dialog.show("EDT Exception", "Please be patient, report the following ERROR to the developers and then kill the app:\n\n" + e.getSource().toString(), null, null);
        });

        // Custom EasyThread error handling
        EasyThread.addGlobalErrorListener((t, c, e) -> {
            CN.callSerially(() -> {
                Log.p("\n\n--- Easy Thread CRASH REPORT ---\n", Log.ERROR);
                Log.p("Thead name: " + Thread.currentThread().getName());
                Log.e(e);
                Server.sendLogAsync();
                Dialog.show("EDT Exception", "Please be patient, report the following ERROR to the developers and then kill the app:\n\n" + e.getMessage(), null, null);
            });
        });

Code to test EDT:

CN.callSerially(() -> {
            throw new IllegalStateException("Example of IllegalStateException in EDT");
        })

Code to test EasyThread:

thread.run(() -> {
            throw new IllegalStateException("Example of IllegalStateException in EasyThread");
        });

As you can guess, Server.sendLogAsync() is my own implementation of Log.sendLogAsync(). Moreover, I disabled the crash protection because I want to force the testers to kill the app when an unmanaged exception occurs.

My questions:

  1. Is this code correct? I note that it works as I except on Android and on iOS, but Simulator becomes unresponsive when an exception inside an EasyThead is thrown. Moreover, the Simulator doesn't show the Dialog when an EasyThread exception is handled, while Android and iOS show it.

  2. What is the usage of the EasyThread t and of the <T> callback as parameters of the method onError(EasyThread t, T callback, Throwable error) of EasyThread.ErrorListener<T>? What is T in this case?

Thanks for the clarifications


Solution

  • The thread name is incorrect in the handling code, you would have printed out the EDT always:

        // Custom EasyThread error handling
        EasyThread.addGlobalErrorListener((t, c, e) -> {
            String threadName = Thread.currentThread().getName();
            CN.callSerially(() -> {
                Log.p("\n\n--- Easy Thread CRASH REPORT ---\n", Log.ERROR);
                Log.p("Thead name: " + threadName);
                if(e != null) {
                      Log.e(e);
                }
                Server.sendLogAsync();
                Dialog.show("EDT Exception", "Please be patient, report the following ERROR to the developers and then kill the app:\n\n" + e.getMessage(), null, null);
            });
        });
    

    The simulator error is odd, I'd very much like to know what happens for that case. If this is reproducible in a debugger this should probably be easy to track.

    • The EasyThread gives you a direct reference to the thread pool that triggered the error.

    • The callback is essentially the Runnable or similar interface we were running e.g. RunnableWithResult. So T indicates the type of the interface. You can make it Object to keep things general.