Search code examples
javaandroidlambdareturn

Lambda expression returns parent method


I'm trying to create a Snackbar in my Android Java application. It has an action, displayed as Cancel, that should stop (or return) the parent method.

I tried this:

snackbar.setAction("Cancel", v -> { return; });

But Android Studio told me that

'return' is unnecessary as the last statement in a 'void' method

showing me that this was returning from the lambda expression, not it's parent method. I also tried super.return;, but that caused a whole lot of errors.


Solution

  • NB: This answer applies generally to UI frameworks/java, not android in particular.

    What you want to do here makes fundamentally no sense.

    The setAction method is telling the snackbar object: Hey, whenever the "Cancel" event occurs, run this code. Don't run it now, run it later. Maybe a year later, when the user bothers to click that cancel button, when this method is long gone - this method where I am informing you what to do when the user clicks that Cancel button, NOT actually doing the act that must be done when the user clicks that, maybe they never click it, after all!

    Hence, 'return from this method' is fundamentally nonsensical. How? That method's probably already done ages ago.

    After telling the object referred to by the snackbar variable what to do when the user presses cancel (which is a near instant operation, of course, and requires no user interaction or anything else that would take more than nanoseconds), this method will keep going.

    It sounds like you are a bit confused about how to set up these actions.

    Taking a bit of a guess on how this works, there are in broad strokes two obvious things you might do:

    Have a dialog with OK and Cancel buttons

    Nothing should happen until a user clicks one of the two buttons. Once they do, it happens and they can no longer stop that short of hard-killing your app or force-shutting down the phone.

    In this case, you should have one call to .setAction("Cancel", ...) and one call to .setAction("OK", ....) and that's that. The cancel button just needs to dismiss the dialog and do nothing else.

    Have a dialog with perhaps a progress bar and a cancel button

    As in, the act occurs right now but will take a while, and you want to offer the user a button to tell your application to abort what it is doing. The dialog is explaining (via a progress bar, spinner, or simply with text) that the act is occurring now and whatever that act may be (say, send an email), once it is done, this dialog dismisses itself (and it is at that point no longer possible to cancel it; possibly it can be undone, but that'd be a separate UI action).

    In this case: You can't just 'kill' a thread mid-stride in java. After all, just hard-killing one process of an app can (and often will) leave stuff in undefined state. Create some concurrency-capable mechanism (in basis, reading the same field from 2 different threads is just broken, because CPUs are mostly self-contained units and forcing them to communicate every change across all cores means there is pretty much no point to multiple cores in the first place, hence, software does not guarantee that writes to a field are seen by other threads unless you explicitly spell it out). Then use that to communicate to the running code that it should abort. that code should then dismiss the dialog.

    The general process for the 'cancel' action code is:

    • Disable the button, both actually (it should no longer invoke the cancel handler), and visually (so the user knows their click is now being handled).
    • Set the concurrency capable flag. Might take the form of interrupting a thread, or setting some AtomicBoolean.
    • that's it. Do nothing else. Leave the dialog up as normal.

    The code that does the slow thing (say, sending mail) should:

    • Set up a system that listens to that flag to abort as soon as it can. How to do this is tricky and depends on what, precisely, you are doing.
    • Once it sees that flag being up / catches InterruptedException, aborts the act, undoes whatever half-work it has done if it can, and it dismisses the dialog entirely. This then lets the user know the act of aborting it has succeeded.