JDeferred는 JQuery의 Deferred Object와 유사한 Java Deferred/Promise 라이브러리입니다.
JQuery 및 Android Deferred Object에서 영감을 얻었습니다.
JDeferred 1.x를 사용하는 경우 JDeferred 1.x 설명서를 참조하세요.
.then(…)
.filter(…)
.pipe(…)
.done(…)
.fail(…)
.progress(…)
.always(…)
.pipeAlways(…)
.when(p1, p2, p3, …).then(…)
.race(p1, p2, p3, …).then(…)
.settle(p1, p2, p3, …).then(…)
.when(new Runnable() {…})
.race(new Runnable() {…})
.settle(new Runnable() {…})
Deferred<Integer, Exception, Double> deferred;
deferred.resolve(10);
deferred.reject(new Exception());
deferred.notify(0.80);
< dependency >
< groupId >org.jdeferred.v2</ groupId >
< artifactId >jdeferred-core</ artifactId >
< version >${version}</ version >
</ dependency >
compile 'org.jdeferred.v2:jdeferred-core:${version}'
Maven Central Repository에서 사용 가능한 버전을 찾아보세요.
버전 간 호환성 보고서:
Deferred deferred = new DeferredObject ();
Promise promise = deferred . promise ();
promise . done ( new DoneCallback () {
public void onDone ( Object result ) {
...
}
}). fail ( new FailCallback () {
public void onFail ( Object rejection ) {
...
}
}). progress ( new ProgressCallback () {
public void onProgress ( Object progress ) {
...
}
}). always ( new AlwaysCallback () {
public void onAlways ( State state , Object result , Object rejection ) {
...
}
});
지연된 객체에 대한 참조를 사용하면 작업/업데이트를 트리거할 수 있습니다.
deferred . resolve ( "done" );
deferred . reject ( "oops" );
deferred . notify ( "100%" );
2.0.0-Beta2부터
.then(...)
대신.filter(...)
사용하십시오.
Deferred d = …;
Promise p = d . promise ();
Promise filtered = p . filter ( new DoneFilter < Integer , Integer >() {
public Integer filterDone ( Integer result )
return result * 10 ;
}
});
filtered . done ( new DoneCallback < Integer >() {
public void onDone ( Integer result ) {
// result would be original * 10
System . out . println ( result );
}
});
d . resolve ( 3 ) -> 30.
2.0.0-Beta2부터
.then(...)
대신.pipe(...)
사용하십시오.
Deferred d = ...;
Promise p = d . promise ();
p . pipe ( new DonePipe < Integer , Integer , Exception , Void >() {
public Deferred < Integer , Exception , Void > pipeDone ( Integer result ) {
if ( result < 100 ) {
return new DeferredObject < Integer , Void , Void >(). resolve ( result );
} else {
return new DeferredObject < Integer , Void , Void >(). reject ( new Exception (...));
}
}
}). done (...). fail (...);
d . resolve ( 80 ) -> done !
d . resolve ( 100 ) -> fail !
DeferredManager dm = new DefaultDeferredManager ();
Promise p1 , p2 , p3 ;
// initialize p1, p2, p3
dm . when ( p1 , p2 , p3 )
. done (…)
. fail (…)
필요에 따라 실행자 서비스를 지정할 수도 있습니다.
DeferredManager dm = new DefaultDeferredManager(myExecutorService);
추가 작업 없이 Callable 및 Runnable을 거의 Promise처럼 사용할 수 있습니다.
DeferredManager dm = new DefaultDeferredManager ();
dm . when ( new Callable < Integer >(){
public Integer call () {
// return something
// or throw a new exception
}
}). done ( new DoneCallback < Integer >() {
public void onDone ( Integer result ) {
...
}
}). fail ( new FailCallback < Throwable >() {
public void onFail ( Throwable e ) {
...
}
});
Callable 또는 Runnable 내에서 진행 상황을 알려야 하는 경우 자체 Deferred 객체와 Promise를 생성하거나 DeferredCallable 및 DeferredRunnable을 사용할 수 있습니다.
자신만의 Deferred 객체를 사용하세요
final Deferred deferred = ...
Promise promise = deferred . promise ();
promise . then (…);
Runnable r = new Runnable () {
public void run () {
while (…) {
deferred . notify ( myProgress );
}
deferred . resolve ( "done" );
}
}
또는 DeferredRunnable을 확장합니다.
DeferredManager dm = …;
dm . when ( new DeferredRunnable < Double >(){
public void run () {
while (…) {
notify ( myProgress );
}
}
}). then (…);
1.0.1 이후
일반적으로 이 프레임워크를 사용할 때 작업을 비동기적으로 수행하려고 합니다. 그러나 지연된 모든 작업이 완료될 때까지 기다려야 하는 경우 Object.wait 또는 Promise.waitSafely 메서드를 사용할 수 있습니다.
Promise p = dm . when (...)
. done (...)
. fail (...)
synchronized ( p )
while ( p . isPending ()) {
try {
p . wait ();
} catch ( InterruptedException e ) { ... }
}
}
또는 보다 간단한 단축키를 사용할 수 있습니다.
Promise p = dm . when (...)
. done (...)
. fail (...)
try {
p . waitSafely ();
} catch ( InterruptedException e ) {
...
}
이제 Java 8 Lambda와 함께 사용하면 매우 멋집니다!
dm . when (() -> {
return "Hey!" ;
}). done ( r -> System . out . println ( r ));
dm . when (
() -> { return "Hello" ; },
() -> { return "World" ; }
). done ( rs ->
rs . forEach ( r -> System . out . println ( r . getResult ()))
);
여러 인수를 사용하여 when
을 호출하면 첫 번째 거부 시 신호가 fail
하거나 모든 계산된 값으로 신호가 done
Promise
발생합니다.
Callable < Integer > c1 = () -> 1 ;
Callable < Integer > c2 = () -> 2 ;
Callable < Integer > c3 = () -> 3 ;
Promise < MultipleResults3 < Integer , Integer , Integer >, OneReject < Throwable >, MasterProgress > p = dm . when ( c1 , c2 , c3 );
p . done ( MultipleResults3 < Integer , Integer , Integer > r -> {
Assert . assertEquals ( r . getFirst (), 1 );
Assert . assertEquals ( r . getSecond (), 2 );
Assert . assertEquals ( r . getThird (), 3 );
});
Callable < Integer > c1 = () -> 1 ;
Callable < Integer > c2 = () -> 2 ;
Callable < Integer > c3 = () -> throw new RuntimeException ( "boom!" );
Promise < MultipleResults3 < Integer , Integer , Integer >, OneReject < Throwable >, MasterProgress > p = dm . when ( c1 , c2 , c3 );
p . done ( MultipleResults3 < Integer , Integer , Integer > r -> Assert . fail ( "should not be called" ))
. fail ( OneReject < Throwable > r -> Assert . assertEquals ( r . getReject (). getMessage (), "boom!" ));
2.0.0 이후
여러 인수(최대 5개)를 사용하여 when
호출하면 형식이 안전한 getter를 사용하여 결과가 생성됩니다.
2.0.0 이후
여러 인수를 사용하여 race
를 호출하면 첫 번째 거부 시 신호가 fail
하거나 첫 번째 해결 시 신호가 done
Promise
발생합니다.
Callable < Integer > c1 = () -> { Thread . sleep ( 200 ); return 1 ; };
Callable < Integer > c2 = () -> { Thread . sleep ( 100 ); return 2 ; };
Callable < Integer > c3 = () -> { Thread . sleep ( 200 ); return 3 ; };
Promise < OneResult <?>, OneReject < Throwable >, Void > p = dm . race ( c1 , c2 , c3 );
p . done ( OneResult <?> r -> Assert . assertEquals ( r . getResult (), 2 ));
Callable < Integer > c1 = () -> { Thread . sleep ( 200 ); return 1 ; };
Callable < Integer > c2 = () -> { Thread . sleep ( 100 ); throw new RuntimeException ( "boom!" ); };
Callable < Integer > c3 = () -> { Thread . sleep ( 200 ); return 3 ; };
Promise < OneResult <?>, OneReject < Throwable >, Void > p = dm . race ( c1 , c2 , c3 );
p . done ( OneResult <?> r -> Assert . fail ( "should not be called" )
. fail ( OneReject < Throwable > r -> Assert . assertEquals ( r . getReject (). getMessage (), "boom!" ));
2.0.0 이후
여러 인수로 settle
호출하면 모든 해결 및 거부를 수집하는 Promise
생성됩니다.
Callable < Integer > c1 = () -> { Thread . sleep ( 200 ); return 1 ; };
Callable < Integer > c2 = () -> { Thread . sleep ( 100 ); throw new RuntimeException ( "boom!" ); };
Callable < Integer > c3 = () -> { Thread . sleep ( 200 ); return 3 ; };
Promise < AllValues , Throwable , MasterProgress >, Void > p = dm . race ( c1 , c2 , c3 );
p . done ( AllValues r -> {
Assert . assertEquals ( r . get ( 0 ). getValue (), 1 );
Assert . assertTrue ( r . get ( 1 ). getValue () instanceof RuntimeException );
Assert . assertEquals ( r . get ( 2 ). getValue (), 3 );
});
2.0.0 이후
때로는 작업이 실행되는 동안 취소될 수 있으며 할당된 리소스를 정리해야 할 수도 있습니다. org.jdeferred2.CancellationHandler
인터페이스를 구현하는 작업을 정의하거나 이러한 구현을 사용하여 DeferredFutureTask
에 추가 인수를 전달할 수 있습니다. 예를 들어
final DataSource datasource = ...;
class DatabaseTask extends Runnable , CancellationHandler {
@ Override
public void run () {
// perform computation with datasource
}
@ Override
public void onCancel () {
try {
datasource . close ();
} catch ( Exception e ) {
throw new IllegalStateException ( e );
}
}
}
DeferredFutureTask < X > task = new DeferredFutureTask ( new DatabaseTask ());
dm . when ( task ). done (...)
CancellationHandler
를 추가 인수로 전달할 수도 있습니다. 예를 들면 다음과 같습니다.
final DataSource datasource = ...;
class DatabaseTask extends Runnable {
@ Override
public void run () {
// perform computation with datasource
}
}
class DatabaseCancellationHandler implements CancellationHandler {
@ Override
public void onCancel () {
try {
datasource . close ();
} catch ( Exception e ) {
throw new IllegalStateException ( e );
}
}
}
DeferredFutureTask < X > task = new DeferredFutureTask ( new DatabaseTask (), new DatabaseCancellationHandler ());
dm . when ( task ). done (...)
Groovy와도 쉽게 사용할 수 있어요!
@Grab ( ' org.jdeferred.v2:jdeferred-core:2.0.0 ' )
import org.jdeferred2.*
import org.jdeferred2.impl.*
def deferred = new DeferredObject ()
def promise = deferred . promise()
promise . done { result ->
println " done: $r esult "
} . fail { rejection ->
println " fail: $r ejection "
} . always { state , result , rejection ->
println " always "
}
deferred . resolve( " done " )
1.1.0-Beta1 이후
이제 jdeferred-android
사용할 수 있으며 다른 Android 라이브러리와 마찬가지로 포함될 수 있습니다! 또한 Android Maven 플러그인을 사용하고 apklib 파일을 빌드합니다. Android Maven 플러그인을 사용하는 경우 종속성을 포함할 수 있습니다.
Maven을 사용한 APKLIB:
< dependency >
< groupId >org.jdeferred.v2</ groupId >
< artifactId >jdeferred-android</ artifactId >
< version >${version}</ version >
< type >apklib</ type >
</ dependency >
Maven을 사용한 AAR:
1.2.0-Beta1 이후
< dependency >
< groupId >org.jdeferred.v2</ groupId >
< artifactId >jdeferred-android-aar</ artifactId >
< version >${version}</ version >
< type >aar</ type >
</ dependency >
Gradle을 사용한 AAR:
compile 'org.jdeferred.v2:jdeferred-android-aar:${version}'
// or
compile 'org.jdeferred.v2:jdeferred-android-aar:${version}@aar'
Maven Central Repository에서 사용 가능한 버전을 찾아보세요.
jdeferred-android
AndroidDeferredManager
라는 새로운 DeferredManager
구현을 도입합니다. AndroidDeferredManager
콜백이 UI 업데이트를 수행할 수 있도록 백그라운드 스레드가 아닌 UI 스레드에서 콜백이 실행되는지 확인합니다. 또는 콜백이 AndroidExecutionScopeable
인터페이스를 구현하여 콜백이 UI 스레드에서 실행되어야 하는지 아니면 백그라운드 스레드에서 실행되어야 하는지를 세밀하게 제어할 수도 있습니다.
AndroidDeferredManager
새로운 DeferredAsyncTask
객체도 지원합니다. 이 개체는 Android의 AsyncTask
기반으로 합니다.
항상 백그라운드 스레드에서 콜백을 실행해야 하는 경우 DefaultDeferredManager
계속 사용할 수 있습니다.
마지막으로 JDeferred는 SLF4J를 사용하므로 slf4j-android
사용하여 로그 메시지를 추가로 라우팅할 수 있습니다.
다음은 비동기 서블릿과 함께 JDeferred를 사용하는 방법에 대한 샘플 코드입니다!
@ WebServlet ( value = "/AsyncServlet" , asyncSupported = true )
public class AsyncServlet extends HttpServlet {
private static final long serialVersionUID = 1L ;
private ExecutorService executorService = Executors . newCachedThreadPool ();
private DeferredManager dm = new DefaultDeferredManager ( executorService );
protected void doGet ( HttpServletRequest request ,
HttpServletResponse response ) throws ServletException , IOException {
final AsyncContext actx = request . startAsync ( request , response );
dm . when ( new Callable < String >() {
@ Override
public String call () throws Exception {
if ( actx . getRequest (). getParameter ( "fail" ) != null ) {
throw new Exception ( "oops!" );
}
Thread . sleep ( 2000 );
return "Hello World!" ;
}
}). then ( new DoneCallback < String >() {
@ Override
public void onDone ( String result ) {
actx . getRequest (). setAttribute ( "message" , result );
actx . dispatch ( "/hello.jsp" );
}
}). fail ( new FailCallback < Throwable >() {
@ Override
public void onFail ( Throwable exception ) {
actx . getRequest (). setAttribute ( "exception" , exception );
actx . dispatch ( "/error.jsp" );
}
});
}
}
DeferredManager.StartPolicy.MANAUL
DeferredManager.StartPolicy.MANUAL
사용하세요.