Android Deferred Object


Source link: https://github.com/CodeAndMagic/android-deferred-object

Android Deferred Object

Android-Deferred-Object is a chainable utility object that can register multiple callbacks into callback queues, invoke callback queues, and relay the success or failure state of any synchronous or asynchronous function.

It's similar to the DeferredObject in jQuery which in turn is bassed on the CommonJS Promises/A design. In most cases the names of the functions are preserved as in jQuery so there's no confusion for those that already know the pattern. Obviously some things needed to be changed because of the lack of anonymous functions and the strong types in Java.

How does it work

Well, simply put when you call a function that needs to execute asynchronously you get back a Promise object. On this promise you can attach callbacks that will get fired in case of success/failure/progress notifications. Whenever the piece of code that was executing asynchronously finishes as expected the Promise is called to be resolved. If some error occurred that promise is called to be rejected.

You can keep a promise long after the execution of the asynchronous code has ended and keep adding callbacks to it. In this case the callbacks will get fired immediately.

You can merge these promise objects into a MergePromise in order to attach a callback to be executed when several promises are resolved.

You can pipe promises so the pieces of asynchronous code gets executed serially like it would have been synchronous.

Why are you using both Promise and DeferredObject terms?

A Promise is a immutable version of a DeferredObject. All DeferredObjects are Promises which is the most generic term and it's preferred. Not all Promises are necessarily a DeferredObject.

On a DeferredObject you have access to the actual resolve and reject methods which is obviously useful when you want to write your own Deferred. But most library code should return a Promise to prevent users of that library to mess with the internal workings of the library. For example in case of a async HTTP call if would be weird if someone other than the actual piece of code that does the HTTP call fires the resolved callbacks.

Why/When should I use the Deferred Object / Promise pattern?

The DeferredObject/Promise pattern can help you to better organise your code, especially the asynchronous type. It also makes it really easy to merge and pipe the execution of different pieces of asynchronous code, which otherwise would get really messy to code.

We also have wrappers for common Android tasks like AsyncTask which makes it trivial to use Promise/DeferredObject in an Android program and combine that with your own DeferredObjects.

In fact we think that DeferredObject makes handling of async code so easy that it encourages your to use more of it which will improve the responsiveness of your app.

Common Use Cases

Success and Failure callbacks for a task

Let's say you need to do something asynchronously like a HTTP request. You can wrap that request into a DeferredAsyncTask and attach callbacks to this action. (note that for HTTP requests we provide you with DeferredHttpUrlConnection or DeferredHttpRequest which makes it even more easy to use but we'll exemplify this scenario with a DeferredAsyncTask so you get the hang of how the pattern works and how you can extend it for your own purposes).

new DeferredAsyncTask<HttpResponse,HttpResponse,Void>() {

  protected abstract Success doInBackground() throws Exception {

  //do your async code here
  
}
 
}
 .done( new ResolveCallback<HttpResponse> {

  public void onResolve(HttpResponse resolved) {

  //your success code here
  
}
 
}
) .fail ( new RejectCallback<HttpResponse> {

  public void onReject(HttpResponse rejected) {

  //your failure code here
  
}
 
}
);

See the main article on Promise-Callbacks to see how you can add multiple success or failure callbacks, how to add callbacks that get triggered both in case of success and failure, how to add a callback that will get triggered for progress notifications and how you can add callbacks for activities that already finished.

Merging several promises

Let's say that you need to do several async tasks and when they're all done you want to execute a piece of code. You can easily handle this my merging those promises with the DeferredObject.when method.

Promise<A1,B1,C1> p1 = new DeferredAsyncTask<A1,B1,C1>() {
 ... 
}
;  Promise<A2,B2,C2> p1 = new DeferredAsyncTask<A2,B2,C2>() {
 ... 
}
; Promise<A3,B3,C3> p3 = new DeferredAsyncTask<A3,B3,C3>() {
 ... 
}
; //when gives you a new promise that gets triggered when all the merged promises are resolved or one of them fails DeferredObject.when(p1,p2,p3) .done(new ResolveCallback<MergedPromiseResult3<A1,A2,A3>() {

  public void onResolve(MergedPromiseResult3<A1,A2,A3> resolved){

Log.i(TAG, "got: " + resolved.first() + resolved.second() + resolved.third());

  
}
 
}
) .fail(new RejectCallback<MergedPromiseReject>() {

  public void onReject(MergedPromiseReject rejected) {

//failure handling here
  
}
 
}
) .progress(new ProgressCallback<MergedPromiseProgress>() {

  public void onProgress(final MergedPromiseProgress progress){

 //you get notified as the merged promises keep coming in
  
}
 
}
);
 //Merging doesn't stop you do add individual callbacks for promises that are in the merge p1.done(...).fail(...) //Or even merging them in another way DeferredObject.when(p1,p2).done(...).fail(...)

See the main article on Merging Promises

Piping and filtering deferreds

Let's say that you need to do an async piece of code, like a HTTP call, in response to another async piece of code. Obviously you could write the dependant call in the done callback of the first call, and sometimes that's the right approach. However now you will be forced to write the code that adds the callbacks to the second call in the done callback of the first one. If you have several of these dependencies it will get (horizontally) awkward really fast.

new DeferredAsyncTask<HttpResponse,HttpResponse,Void>() {
...
}
 .done( new ResolveCallback<HttpResponse> {

  public void onResolve(HttpResponse resolved) {

//callback to first call here

new DeferredAsyncTask<HttpResponse,HttpResponse,Void>() {
...
}

.done(

 //callback to second call here

 new DeferredAsyncTask<HttpResponse,HttpResponse,Void>() {
...
}

 .done(

  //callback to third call here

 );

);

}
 
}
);

Instead you can pipe the first call with the second. Piping gives you a promise that doesn't exist yet so you can attach callbacks on it in a chain.

new DeferredAsyncTask<HttpResponse,HttpResponse,Void>() {
...
}
 .done( /* callback to first call here */ ) .pipe(new ResolvePipe<HttpResponse,HttpResponse,Void>() {

  public Promise<HttpResponse,HttpResponse,Void> pipeResolved(HttpResponse response1){

  return new DeferredAsyncTask<HttpResponse,HttpResponse,Void>() {
 ... 
}

  
}
 
}
) .done( /* callback to second call here */ ) .pipe(new ResolvePipe<HttpResponse,HttpResponse,Void>() {

  public Promise<HttpResponse,HttpResponse,Void> pipeResolved(HttpResponse response1){

  return new DeferredAsyncTask<HttpResponse,HttpResponse,Void>() {
 ... 
}

  
}
 
}
) .done( /* callback to third call here */ )

See the main article on Piping Promises

What are those generics you keep throwing around?

See the main article on The Promise Interface

Resources

This application is example of Android Architecture Components which implements MVVM Pattern.

Configurable typing indicator for Android

A lightweight Android library for customizable alerts.

RxJava2 based caching mechanism. Simple to use yet very powerful.

Key features:

  • Customizable
  • Fast
  • Reliable

An easy to use wrapper of the native Android Snackbar which stays visible across multiple activities. It provides different themes to start with, and allows you to easily manage common scenarios like success, warning, error, info.

An easy file / folder picker dialog fragment which is easily to implement. Nothing special is required, you just need to add few lines of code!

Topics


2D Engines   3D Engines   9-Patch   Action Bars   Activities   ADB   Advertisements   Analytics   Animations   ANR   AOP   API   APK   APT   Architecture   Audio   Autocomplete   Background Processing   Backward Compatibility   Badges   Bar Codes   Benchmarking   Bitmaps   Bluetooth   Blur Effects   Bread Crumbs   BRMS   Browser Extensions   Build Systems   Bundles   Buttons   Caching   Camera   Canvas   Cards   Carousels   Changelog   Checkboxes   Cloud Storages   Color Analysis   Color Pickers   Colors   Comet/Push   Compass Sensors   Conferences   Content Providers   Continuous Integration   Crash Reports   Credit Cards   Credits   CSV   Curl/Flip   Data Binding   Data Generators   Data Structures   Database   Database Browsers   Date &   Debugging   Decompilers   Deep Links   Dependency Injections   Design   Design Patterns   Dex   Dialogs   Distributed Computing   Distribution Platforms   Download Managers   Drawables   Emoji   Emulators   EPUB   Equalizers &   Event Buses   Exception Handling   Face Recognition   Feedback &   File System   File/Directory   Fingerprint   Floating Action   Fonts   Forms   Fragments   FRP   FSM   Functional Programming   Gamepads   Games   Geocaching   Gestures   GIF   Glow Pad   Gradle Plugins   Graphics   Grid Views   Highlighting   HTML   HTTP Mocking   Icons   IDE   IDE Plugins   Image Croppers   Image Loaders   Image Pickers   Image Processing   Image Views   Instrumentation   Intents   Job Schedulers   JSON   Keyboard   Kotlin   Layouts   Library Demos   List View   List Views   Localization   Location   Lock Patterns   Logcat   Logging   Mails   Maps   Markdown   Mathematics   Maven Plugins   MBaaS   Media   Menus   Messaging   MIME   Mobile Web   Native Image   Navigation   NDK   Networking   NFC   NoSQL   Number Pickers   OAuth   Object Mocking   OCR Engines   OpenGL   ORM   Other Pickers   Parallax List   Parcelables   Particle Systems   Password Inputs   PDF   Permissions   Physics Engines   Platforms   Plugin Frameworks   Preferences   Progress Indicators   ProGuard   Properties   Protocol Buffer   Pull To   Purchases   Push/Pull   QR Codes   Quick Return   Radio Buttons   Range Bars   Ratings   Recycler Views   Resources   REST   Ripple Effects   RSS   Screenshots   Scripting   Scroll Views   SDK   Search Inputs   Security   Sensors   Services   Showcase Views   Signatures   Sliding Panels   Snackbars   SOAP   Social Networks   Spannable   Spinners   Splash Screens   SSH   Static Analysis   Status Bars   Styling   SVG   System   Tags   Task Managers   TDD &   Template Engines   Testing   Testing Tools   Text Formatting   Text Views   Text Watchers   Text-to   Toasts   Toolkits For   Tools   Tooltips   Trainings   TV   Twitter   Updaters   USB   User Stories   Utils   Validation   Video   View Adapters   View Pagers   Views   Watch Face   Wearable Data   Wearables   Weather   Web Tools   Web Views   WebRTC   WebSockets   Wheel Widgets   Wi-Fi   Widgets   Windows   Wizards   XML   XMPP   YAML   ZIP Codes