Deferred is a fork of Ray Tsang's JDeferred library inspired in JQuery
The purpose of the library is to provide an easy-to-use implementation of promised for Android applications with an architecture based on pools. In Tuenti we have an architecture where the developer is the responsible of known in which thread pool should his code be executed, in a similar way to RxJava, we distinguish between network, disk, computation or UI work, and we wanted a Promise implementation that let us work in that way easily.
- Deferred object and Promise
- Promise callbacks
.then(…)
.done(…)
.fail(…)
.progress(…)
.always(…)
- Multiple promises
.when(p1, p2, p3, …).then(…)
- Callable and Runnable wrappers
.when(new Runnable() {…})
- Uses Executor Service
- Java Generics support
Deferred<Integer, Exception, Double> deferred;
deferred.resolve(10);
deferred.reject(new Exception());
deferred.notify(0.80);
Deferred<Integer, Exception, Void> deferred = deferredFactory.build();
deferred.resolve(1);
Promise<Integer, Exception, Void> promise = deferred.promise();
promise.done((Done.Immediately<Integer>) i -> System.out.println(i));
As you can see, Done.Immediately<Integer>
is the type of Done callback that we want to use, for the callbacks, you can use:
- Immediately: To be run in the same thread where the promise has been resolved.
- UI: To run it on UI thread.
- Computation: To run it on the computation pool.
- Disk: To run it on disk pool.
- Network: To run it on network pool.
The promises are asynchronous, the callbacks can be set before/after the promise is finished
Deferred<String, Exception, Void> deferred = deferredFactory.build();
deferred.done((Done.UI<String>) result -> System.out.println(result));
deferred.resolve("Finish!");
Deferred<Integer, Void, Void> deferred = deferredFactory.build();
deferred.resolve(1);
deferred.then((Done.Filter.Computation<Integer, Integer>) i -> i * 2)
.done((Done.UI<Integer>) i -> System.out.println(i));
Deferred<Integer, Void, Void> deferred = deferredFactory.build();
deferred.resolve(1);
deferred.then((Computation<Integer, Integer, Exception, Void>) i ->
deferredFactory.<Integer, Exception, Void>build().reject(new Exception()))
.done((UI<Integer>) i -> System.out.println(i))
.fail((Fail.UI<Exception>) e -> System.out.println("Uh oh!"));
Deferred<Integer, Void, Void> deferred = deferredFactory.build();
deferred.resolve(1);
deferred.then((Done.Pipe.Computation<Integer, Integer, Exception, Void>) i -> {
Deferred<Integer, Exception, Void> positiveDeferred = deferredFactory.build();
positiveDeferred.resolveOrReject(i > 0, i, new Exception("Noooo"));
return positiveDeferred;
})
.then((Done.Filter.Computation<Integer, String>) i -> "Result is " + String.valueOf(i))
.done((Done.UI<String>) i -> System.out.println(i))
.fail((Fail.UI<Exception>) e -> System.out.println(e.getMessage()));
}
You can use a DeferredManager
implementation, DefaultDeferredManager
or your custom one to combine the execution of several promises
for example:
DeferredManager dm = new DefaultDeferredManager();
Promise p1, p2, p3;
// initialize p1, p2, p3
dm.when(p1, p2, p3)
.done(…)
.fail(…)
Or use sequentiallyRunUntilFirstDone
to execute sequentially the promises until one is resolved:
For this you must instantiate some objects implementing PromiseObjectTask<D, F, P>
for example:
private PromiseObjectTask<Data, Exception, Void> getDataFromMemory() {
return new PromiseObjectTask<Data, Exception, Void>() {
@Override
public Promise<Data, Exception, Void> run() {
return inMemoryStorage.getData();
}
};
}
private PromiseObjectTask<Data, Exception, Void> getDataFromDisk() {
return new PromiseObjectTask<Data, Exception, Void>() {
@Override
public Promise<Data, Exception, Void> run() {
return diskStorage.getData();
}
};
}
private PromiseObjectTask<Data, Exception, Void> getDataFromAPI() {
return new PromiseObjectTask<Data, Exception, Void>() {
@Override
public Promise<Data, Exception, Void> run() {
return apiClientStorage.getData();
}
};
}
deferredManager.sequentiallyRunUntilFirstDone(getDataFromMemory(),
getDataFromDisk(),
getDataFromAPI());
or avoiding verbosity using lambdas or method references:
deferredManager.sequentiallyRunUntilFirstDone(inMemoryStorage::getData,
diskStorage::getData,
apiClient::getData);
Also, you can use lazyAnd
or lazyOr
to execute promises sequentially until the boolean condition is achieved.
The promises are created via a DeferredFactory
, to create an instance of this class you should provide an implementation of ExecutorProvider
, this class will is where you will tell Deferred in which pool you want to execute your code, for example:
import java.util.concurrent.Executor;
import com.tuenti.deferred.ExecutorProvider;
public class MyExecutorProvider implements ExecutorProvider {
private final Executor myExecutor = new Executor() {
@Override
public void execute(Runnable command) {
command.run();
}
};
@Override
public Executor getUiExecutor() {
return myExecutor;
}
@Override
public Executor getComputationExecutor() {
return myExecutor;
}
@Override
public Executor getDiskExecutor() {
return myExecutor;
}
@Override
public Executor getNetworkExecutor() {
return myExecutor;
}
}