A Promise library for android which follows Promise/A+ standard
Nearly, all android promise open-source projects offer us a tool, which has async-thread-execution being involved
into their component. I must say, it is good, since AsyncTask is just like that - executing tasks in
a pre-built task-executors, or let user provide one for AsyncTask. But I think, Promise should just focus on
async processing functions with callbacks, without making any extra thread or using executors to handle runnable
or Callable process.
The Promise lib here dose not do any thread-making stuff, or not depends on any executors. It just produce a
Deferred object, letting you decide when to resolve a deferred or reject a deferred. Then making then on
a desired looper thread.
If you want your runnable to be running asynchronously, just make your own thread to take charge of running and
remember to resolve or reject the result.
While in thenable method, you should supply us a resolver which can turn the promise result into another promise
just like Promise in javascript.
And, The Promise lib here also provide us a lot of features that js promise owns too. Here is the example:
public class PromiseTest {
public static void main(String...args) {
Promise<Integer> p1 = Promise.make(new DirectFunction<Integer>() {
@Override
public void run(final Locker<Integer> locker) {
new Thread() {
public void run() {
try {
System.out.println("p1 is running");
Thread.sleep(5000);
} catch (InterruptedException e) {
locker.reject(e);
}
locker.resolve(100);
System.out.println("p1 is over");
}
}.start();
}
});
Promise<Object> px = Promise.make(new DirectFunction<Object>() {
@Override
public void run(Locker<Object> locker) {
locker.reject(new TimeoutException("timeout"));
}
}).exception(new ExceptionResolver<Object, TimeoutException>() {
@Override
public Object onCatch(TimeoutException exception) {
exception.printStackTrace();
throw Promise.newException(exception);
}
});
px.exception(new ExceptionPromiseResolver<Object, InterruptedException>() {
@Override
public Promise<Object> onCatch(InterruptedException exception) {
throw Promise.newException(new IOException());
}
});
Promise<Integer> p1p = p1.clone();
Promise<Integer> p2 = Promise.make(new DirectFunction<Integer>() {
@Override
public void run(final Locker<Integer> locker) {
new Thread() {
public void run() {
try {
System.out.println("p2 is running");
Thread.sleep(4000);
} catch (InterruptedException e) {
locker.reject(e);
}
locker.resolve(100);
System.out.println("p2 is over");
}
}.start();
}
});
ArrayList<Promise<?>> list = new ArrayList<Promise<?>>();
list.add(p1);
list.add(p1p);
list.add(p2);
Promise.race(list).then(new DirectResolver<Object, Void>() {
@Override
public Void resolve(Object newValue) {
System.out.println("race complete" + newValue);
return null;
}
@Override
public Void reject(Exception exception) {
return null;
}
});
p1.then(new DirectResolver<Integer, String>() {
@Override
public String resolve(Integer newValue) {
System.out.println(newValue);
return "p1 resolved";
}
@Override
public String reject(Exception exception) {
throw Promise.newException(exception);
}
}).then(new SimplePromiseResolver<String, Integer>() {
@Override
public Promise<Integer> resolve(String newValue) {
System.out.println(newValue);
return Promise.make(new DirectFunction<Integer>() {
@Override
public void run(final Locker<Integer> locker) {
new Thread() {
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
locker.reject(e);
}
locker.resolve(3000);
}
}.start();
}
});
}
}).then(new SimpleResolver<Integer, Integer>() {
@Override
public Integer resolve(Integer newValue) {
System.out.println("then resolve a new value=" + newValue);
return null;
}
}).then(new SimpleResolver<Number, Integer>() {
@Override
public Integer resolve(Number newValue) {
return null;
}
});
// making a deferred, then use defer to propagate a promise
final PromiseDeferred<Integer> defer = PromiseDeferred.make();
final PromiseDeferred<String> defer2 = PromiseDeferred.make();
defer.promise().then(new SimpleResolver<Integer, Void>() {
@Override
public Void resolve(Integer newValue) {
System.out.println("Defer:::" + newValue);
return null;
}
}).exception(new ExceptionResolver<Void, NullPointerException>() {
@Override
public Void onCatch(NullPointerException exception) {
exception.printStackTrace();
return null;
}
}).exception(new ExceptionResolver<Void, TimeoutException>() {
@Override
public Void onCatch(TimeoutException exception) {
exception.printStackTrace();
return null;
}
});
new Thread() {
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
defer.reject(e);
}
defer.reject(new TimeoutException("defer timeout"));
}
}.start();
Thenable<Integer> th = p1;
Thenable<Integer> th2 = th.then(new SimpleResolver<Number, Integer>() {
@Override
public Integer resolve(Number newValue) {
return 4;
}
});
Thenable<Number> th3 = th2.cast();
th3.then(new SimpleResolver<Number, String>() {
@Override
public String resolve(Number newValue) {
System.out.println(newValue);
return String.valueOf(newValue);
}
}).then(defer2);
PromiseFactory.create(new DirectFunction<String>() {
@Override
public void run(Locker<String> locker) {
locker.resolve("444");
}
}).make().then(defer2);
Promise<Integer> intPromise = Promise.resolve(5);
Promise<Integer> exPromise = Promise.reject(new Exception());
Promise<Integer> clonePromise = Promise.resolve(th);
Promise.all(intPromise, exPromise, clonePromise);
}
}Promise.makeis a promise factory method which can make a new promisePromise.allequals to javascriptPromise.allPromise.raceequals to javascriptPromise.racePromise.seriesmeans running functions sequentiallyPromise.resolveequals to javascriptPromise.resolvePromise.rejectequals to javascriptPromise.rejectPromise.newExceptionis to wrap and convert any exception into an internal runtime exceptionPromise.timeoutis to make an n milli-seconds timeout promise
promise.thenequals to javascriptpromise.then, we can resolve async/synchronizedpromise.getThencan make a newDirectFunctionfor making a new android promisepromise.exceptionequals to javascriptpromise.catchpromise.finalResultequals to javascriptpromise.donepromise.castcan safely casting a Promise to a NEW Promise
in javascript, calling then method is as simple as promise.then(resolve, reject)
in java, it's not easy to generate two object-arguments, so let's make it simple, that we can call .then like this
promise.then(resolver) within which the resolver implements two method resolve and reject
The Promise lib provides many pre-built resolvers, and all are based on DirectResolver or PromiseResolver.
The former returns a result directly while the latter returns a promise
DirectResolverturns a result into a new onePromiseResolverturns a result into a promiseSimpleResolverandSimplePromiseResolveronly care about resolving the result, other than popping exceptions on rejectingExceptionResolverandExceptionPromiseResolveronly focus on a specific type of exceptionFinalResolveronly processes the final stuff whenever it is resolved or rejectedDoneResolveronly processes the final stuff with two arguments: exception and resultDeferreda specific resolver which will deliver the result to another deferred callback
PromiseDeferred.makeis a factory method which can make a deferred object extending fromPromise.Lockerwho is also a specific resolver
resolveequals to javascriptdefer.resolve, usually used as a locker in promiserejectequals to javascriptdefer.reject, usually used as a locker in promisedonedetect whether this deferred has been ever invoked resolve or rejectpostequals to androidhandler.post, using the internal handlerpostDelayequals to androidhandler.postDelay, using the internal handlerremoveCallbacksequals to android 'handler.removeCallbacks', using the internal handlerpromiseequals to javascriptdefer.promise, which will generate a promise object who is waiting for the deferred to be resolved
PromiseFactory.createwill make a promise factory with aDirectFunctionto implement
promiseFactory.runis a function you should override when you create your own factory unless you use staticcreatepromiseFactory.makeis to make a new promise, each time you call this, therun(locker)will be executed
Copyright 2016 tangye1234.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
