Class GeckoResult<T>

Object
org.mozilla.geckoview.GeckoResult<T>
Type Parameters:
T - The type of the value delivered via the GeckoResult.

@AnyThread public class GeckoResult<T> extends Object
GeckoResult is a class that represents an asynchronous result. The result is initially pending, and at a later time, the result may be completed with a value or an exception depending on the outcome of the asynchronous operation. For example,
 public GeckoResult<Integer> divide(final int dividend, final int divisor) {
     final GeckoResult<Integer> result = new GeckoResult<>();
     (new Thread(() -> {
         if (divisor != 0) {
             result.complete(dividend / divisor);
         } else {
             result.completeExceptionally(new ArithmeticException("Dividing by zero"));
         }
     })).start();
     return result;
 }

To retrieve the completed value or exception, use one of the then(org.mozilla.geckoview.GeckoResult.OnValueListener<T, U>) methods to register listeners on the result. Listeners are run on the thread where the GeckoResult is created if a Looper is present. For example, to retrieve a completed value,

 divide(42, 2).then(new GeckoResult.OnValueListener<Integer, Void>() {
     @Override
     public GeckoResult<Void> onValue(final Integer value) {
         // value == 21
     }
 }, new GeckoResult.OnExceptionListener<Void>() {
     @Override
     public GeckoResult<Void> onException(final Throwable exception) {
         // Not called
     }
 });

And to retrieve a completed exception,

 divide(42, 0).then(new GeckoResult.OnValueListener<Integer, Void>() {
     @Override
     public GeckoResult<Void> onValue(final Integer value) {
         // Not called
     }
 }, new GeckoResult.OnExceptionListener<Void>() {
     @Override
     public GeckoResult<Void> onException(final Throwable exception) {
         // exception instanceof ArithmeticException
     }
 });

then(org.mozilla.geckoview.GeckoResult.OnValueListener<T, U>) calls may be chained to complete multiple asynchonous operations in sequence. This example takes an integer, converts it to a String, and appends it to another String,

 divide(42, 2).then(new GeckoResult.OnValueListener<Integer, String>() {
     @Override
     public GeckoResult<String> onValue(final Integer value) {
         return GeckoResult.fromValue(value.toString());
     }
 }).then(new GeckoResult.OnValueListener<String, String>() {
     @Override
     public GeckoResult<String> onValue(final String value) {
         return GeckoResult.fromValue("42 / 2 = " + value);
     }
 }).then(new GeckoResult.OnValueListener<String, Void>() {
     @Override
     public GeckoResult<Void> onValue(final String value) {
         // value == "42 / 2 = 21"
         return null;
     }
 });

Chaining works with exception listeners as well. For example,

 divide(42, 0).then(new GeckoResult.OnExceptionListener<String>() {
     @Override
     public GeckoResult<Void> onException(final Throwable exception) {
         return "foo";
     }
 }).then(new GeckoResult.OnValueListener<String, Void>() {
     @Override
     public GeckoResult<Void> onValue(final String value) {
         // value == "foo"
     }
 });

A completed value/exception will propagate down the chain even if an intermediate step does not have a value/exception listener. For example,

 divide(42, 0).then(new GeckoResult.OnValueListener<Integer, String>() {
     @Override
     public GeckoResult<String> onValue(final Integer value) {
         // Not called
     }
 }).then(new GeckoResult.OnExceptionListener<Void>() {
     @Override
     public GeckoResult<Void> onException(final Throwable exception) {
         // exception instanceof ArithmeticException
     }
 });

However, any propagated value will be coerced to null. For example,

 divide(42, 2).then(new GeckoResult.OnExceptionListener<String>() {
     @Override
     public GeckoResult<String> onException(final Throwable exception) {
         // Not called
     }
 }).then(new GeckoResult.OnValueListener<String, Void>() {
     @Override
     public GeckoResult<Void> onValue(final String value) {
         // value == null
     }
 });

If a GeckoResult is created on a thread without a Looper, then(OnValueListener, OnExceptionListener) is unusable (and will throw IllegalThreadStateException). In this scenario, the value is only available via poll(long). Alternatively, you may also chain the GeckoResult to one with a Handler via withHandler(Handler). You may then use then(OnValueListener, OnExceptionListener) on the returned GeckoResult normally.

Any exception thrown by a listener are automatically used to complete the result. At the end of every chain, there is an implicit exception listener that rethrows any uncaught and unhandled exception as GeckoResult.UncaughtException. The following example will cause GeckoResult.UncaughtException to be thrown because BazException is uncaught and unhandled at the end of the chain,

 GeckoResult.fromValue(42).then(new GeckoResult.OnValueListener<Integer, Void>() {
     @Override
     public GeckoResult<Void> onValue(final Integer value) throws FooException {
         throw new FooException();
     }
 }).then(new GeckoResult.OnExceptionListener<Void>() {
     @Override
     public GeckoResult<Void> onException(final Throwable exception) throws Exception {
         // exception instanceof FooException
         throw new BarException();
     }
 }).then(new GeckoResult.OnExceptionListener<Void>() {
     @Override
     public GeckoResult<Void> onException(final Throwable exception) throws Throwable {
         // exception instanceof BarException
         return new BazException();
     }
 });