顯示具有 android 標籤的文章。 顯示所有文章
顯示具有 android 標籤的文章。 顯示所有文章

2016年1月2日 星期六

Practice Reative(Rx) - merge

http://reactivex.io/documentation/operators/merge.html

前言: 最近Rx相關的議題在Android圈特別熱門,除了在Android Weekly裡面的文章幾乎都會擦到邊,又或者很多公司直接把這個架構導入產品之中;對我來說,原本某些code就已經有這個概念的影子,例如Async的操作,我們是用Parse推出的Bolts來實踐Defer/Promise,但Rx的概念更為通用,這表示Async的功能只是其中之一;學習Design Pattern最重要的是套用實際案例,所以以後Practice Reative(Rx)的系列文章,將針對各個component如何套用到實際的問題為目標

今天要聊到merge,其概念就是將數個Observable合併起來,你可以用在把所有Error report的Observable合併,再透過統一方式去處理,而此範例將搭配RxBinding跟map來解決Report Flurry Event的問題。

假設UI(此Sample Code來自好事地圖的專案)有8個按鈕都要report不同的event到flurry,你可以這樣寫(Gist)



如有更多有趣的使用方式歡迎分享。

2015年11月20日 星期五

ANR with Google Analytics when purchasing the in-app-purchase items

     昨天suffer了一個離奇的deadlock issue,情境是如果User已經買過某個IAP Item後,重複購買時有些Device就會卡住然後ANR,結果dump出來Thread的狀態後發現,結果Main Thread卡在在GA回報Crash的Task。

stackoverflow有人建議直接把它回報crash的功能關掉(專心做event的事情就好了啊GA)

http://stackoverflow.com/questions/30654669/anr-with-google-analytics

2015年10月9日 星期五

Develop VR App by Unity3D

前言:因為公司買了一些VR的設備,藉由之前用Unity開發遊戲的經驗,剛好替公司破億下載的派對做一個派對限定的APP。

Unity3D在5.1版後正式支援VR功能,而最近各個VR的平台紛紛做好Unity3D的Plugin,讓開發者能夠專心在處理想要呈現的世界,像Google Cardboard的在這,以及Samsung GearVR的在這,概念大概是把攝影機的Prefab拉到Unity的編輯世界裡就完成了,不過每家VR也有些特殊的功能通常也會提供,像Google Cardboard右邊有個拉環可以拉,它的SDK也包含這個觸發的Prefab。

Google Cardboard可以把程式甚至Deploy到iPhone上,用Cardboard就能得到跟Android一樣的體驗,只能說Google的想法真的很特別(民主);不像Oculus只想著如何綁硬體來賣,雖然用Unity開發,但只有Android而且還要Samsung S6跟Note4才能讓程式跑起來。

最後分享一下我的成品,概念是會把派對時,把大家拍的照片放在一個類似五次元的空間中(靈感來自星際效應的最後片段)。

https://github.com/bearprada/PicCollage100MPartyVRApp


2015年9月21日 星期一

FloatMath在Android M版本不見了

   升級到Android M版本拿掉很多官方覺得不適用的Classes,像是AndroidClient以及FloatMath,只要你將專案的版本升級到23之後就會發現。AndroidClient的問題可以在build.gradle裡面加上:
useLibrary 'org.apache.http.legacy'
    但是FloatMath的問題官方就沒有特別說明處理的方式,而公司的專案剛好用到兩個library都踩到這個雷,它們分別為PhotoViewAviary;如果要等它們升級到最新版本可能要等到天荒地老,而且Aviary最近好像要停止支援,希望大家去另外一套library叫做Adobe Creative SDK(其實跟Aviary長的一模一樣),可能是Adobe正在宣示主權吧!

   最後想到一招可以解決目前的過渡期,那就是自行新增一個android.util.FloatMath.java,然後把Method全部bypass到Math的物件,就能夠安然的編譯完成。


更新:PhotoView在1.2.4把這個問題解決了(commit)

2015年8月23日 星期日

Implementation of Undo/Redo on Android



    最近公司的產品拼貼趣想做Undo(上一步)和Redo(下一步)的功能,因為使用者常常不小心就把拼好的作品誤移,然後又很難移回來,其中一個發想就是參考Photoshop可以做Undo/Redo(還有其他發想例如把某個Layer鎖住的功能),聽起來對現在的code非常有挑戰,但還是花了一個下午做出第一版Prototype(只支援Undo),看起來會動只是畫面會狂閃;後來iOS的同事才跟我介紹他們實作的方式 - UndoManager

    秀了幾行code給我看後,感覺這個設計架構根本就超好,結果Android內建沒有這套實作,結果它藏在Android Framework裡,而且命名規則也很iOS(每一個Command叫做Operation),感覺是給內部UI Widget用的功能。

    解決這類型問題也有常用的Design Pattern,在SO找到這篇推薦Command Pattern,有空再來消化這個Pattern的其他應用方式。


2015年8月22日 星期六

Android Vision library

   Google Play Service 7.8 introduces the android vision library. that can easy to implement the function of face detection and barcode reader. the best part of it is that supports android 2.2 devices. you can checkout the sample code here.

Random idea: the traditional digital camera support smile mode. that means you can take photo by your smile face. now you can do the same thing on the android app. or you can trigger it by a wink

 

Solving the confliction on Android BuildToolsVersion 23 with RenderScript v8 library

If you using renderscript support library, and you try to upgrade the android tools version to 23.0.0. you will get the issue likes when compile your project :

UNEXPECTED TOP-LEVEL EXCEPTION:com.android.dex.DexException: Multiple dex files define Landroid/support/annotation/AnimRes;
at com.android.dx.merge.DexMerger.getSortedTypes(DexMerger.java:554)
at com.android.dx.merge.DexMerger.mergeClassDefs(DexMerger.java:535)
at com.android.dx.merge.DexMerger.merge(DexMerger.java:189)
at com.android.dx.command.dexer.Main.mergeLibraryDexBuffers(Main.java:502)
at com.android.dx.command.dexer.Main.runMonoDex(Main.java:334)
at com.android.dx.command.dexer.Main.run(Main.java:277)
at com.android.dx.command.dexer.Main.main(Main.java:245)
at com.android.dx.command.Main.main(Main.java:106)

it cause the renderscirpt support library includes the annotation library's source code. you can solve this issue by adding a few of code in build.gradle

configurations {
    all*.exclude group: 'com.android.support', module: 'support-annotations'
}

reference : http://stackoverflow.com/questions/32051938/getting-multiple-dex-error-when-using-render-script-support-lib/32090710#32090710

2015年8月1日 星期六

Feedback : Upgrade Android M Preview 2

   最近大膽地將自己的Nexus 6升級到Android M的Preview版本,正所謂第一次將Preview版本用在自己手機就上手,反正也是前陣子才從iPhone換成Android,該遺失的資料也早該丟光光了,正所謂沒什麼很失去的時候,人就會變得特別有勇氣。

以上是用起來的後果:

1. Google Now Launcher瘋狂閃退:只要你用adb裝一次apk它就一定閃退給你看
2. Line已不舉:不知道它用了哪個API來檢查網路狀況,升級過後你永遠沒辦法登入Line的帳號,它只會不停的跟你說: "Please make sure that you have network connectivity and try again",這也表示Line的所有遊戲都GG了
3. 如果你是開發Camera App,可以特別把Camera的permission關掉,當你Call Camera.open()時就會拿不到Camera,請做好error handling,以我們的App(SelfieGrid)來說,雖然不會crash,但就剩黑畫面

如果還有其他後果歡迎與我分享


TabLayout will get empty Tab after upgrade design library to 22.2.1

  Google introduces the design library for making material design easier. so we reimplement the tab component by TabLayout. it's work perfectly in 22.2.0. but we get problem after upgrade the version to 22.2.1. the tab doesn't show up anymore(issue track).

  it's work on some place, but some one isn't. we couldn't figure out what is the right way to handle this. so we decide to rollback the version to 22.2.0.








2015年4月25日 星期六

Fresco : an image management library





    書在F8發表了自己的Image Loader Library(Android)叫做Fresco,因為他們在市面上找不到完全符合需求的Library,所以自己就寫了一個(這邏輯很Facebook),它主要強調功能有五:1)有更佳的記憶體管理、2)支援Progressive JPEG、3)Animation Format(GIF和WebP)、4)Drawing(更整合customize layer:例如想要塞浮水印之類的)以及 5)更加的Loading體驗。

針對第五點想要特別強調:1) 它可以同時設定多種resolution的圖片,讓較低解析度的圖片先秀出、2) 支援EXIF Thumbnail、3) Auto-resize rotation(base on EXIF)、 4) 讓Android 2.3的裝置也支援WebP。

翻了翻它的source code發現,所以decoder都適用NDK寫的,包含jpeg、png、gif跟WebP真的是佛心來著。看來該把原本在用的Ion拔掉了。


2015年4月8日 星期三

GIF Encoder on Android



    近跟臉書的Messenger Platform合作了一款新的APP叫做GIFCAM(希望大家趕快去下載來玩唷!),看APP的名稱就知道跟GIF格式有所相關,今天想要分享(抱怨)在開發中碰到的痛點之一GIF Encoder。

為什麼痛呢?第一沒有官方support的版本(iOS在ImageIO Framework裡);第二有3rd party library是存JAVA的solution,但performance就是差到很誇張;第三想找NDK solution但找不太到標準或比較常用的library。

基於上面的思路,想必要自己把它擠出來了,所以我參考了一個半成品叫做Gifflen,看起來是我們想要的答案,但是,它的code style不太像個OK的library,果然用了之後碰到很多問題,細節之後再透過其他文章跟大家分享,總之為了要達成像iOS ImageIO的效能,我們把GIF的Spec認真的看了一遍,一個一個byte去看iOS為什麼可以做得比較好(之後我們會把自己的Gifflen再open source出來),目前雖然沒有達到一樣,但效能跟輸出結果還差強人意,勉強可以通過測試並且上線。


2014年12月15日 星期一

Material Design I : Floating Action Button (FAB)


  自從Google再Lollipop(5.0)推出後,終於記得順便幫Android穿上漂亮的衣服,那就是 Material Design(MD)最重要的使命,不論是設計的元素、語言跟配色都有了屬於自己的Guildline

    對Android Developer而言,則是遵守官方規矩,就可以自己做出"有點"美感APP,官方BLOG還貼心的準備Check list給開發者(這表示幾乎都有附上source code)。而我們公司的產品也順著這班MD的風潮導入了許多元素,讓原本很iOS的APP找回了自己應有的面貌:> 這篇文章介紹其中一個導入的widget : Floating Action Button(FAB) 

仿間有一大堆自製的牌子, 以下條列使用心得

https://github.com/makovkastar/FloatingActionButton
評論 : 最多star,多做了show/hide的animation,但用在5.0以下的Device會怪怪的(可能是我的project設定有問題)(這是我發的issue ticket),所以最後沒採用這套。


https://github.com/futuresimple/android-floating-action-button
評論: 它是fork上面那個的專案,不過它多做了sub-menu的功能(有點像Path的小紅點, 這也是MD其中一種元素),但沒有包裝show/hide的animation,最後我採用這套,因為他沒有上面的issue(神奇),最後我把上面animation的code搬到這個專案之中,搞定。




2014年10月11日 星期六

Canvas coordinate system

    近加新功能的時,碰到一個在Canvas上座標系統認知上有所不同的地方;一般我們會用 Canvas.drawBitmap(Bitmap, 10, 10, Paint)把一張圖畫在(0,0)的位置,當然這個(0,0)不預期是整個device的(0,0),而是根據View最後被擺放的位置,例如某View被Layout在(100, 100),而Canvas.drawBitmap(Bitmap, 10, 10, Paint)則會畫在螢幕(110,110)的地方。

到目前為止都沒有錯誤,但如果translation的方式是用Matrix,而你的code可能會變成

Matrix matrix = new Matrix();
matrix.postTranslate(10, 10);
canvas.setMatrix(matrix);
Canvas.drawBitmap(Bitmap, matrix, Paint);

此時畫出來的結果就還是會在(10, 10)。原本猜想是忘記apply原本canvas的matrix所致,所以改成

Matrix matrix = new Matrix(canvas.getMatrix());
matrix.postTranslate(10, 10);
canvas.setMatrix(matrix);
Canvas.drawBitmap(Bitmap, matrix, Paint);

結果還是(10,10)!結果不小心喵到有Method叫Canvas.concat()。後來改成:

Matrix matrix = new Matrix(canvas.getMatrix());
matrix.postTranslate(10, 10);
canvas.concat(matrix);
Canvas.drawBitmap(Bitmap, matrix, Paint);

最後就成功的畫在(110,110)的位置。百思不得其解的是:

Matrix matrix = new Matrix(canvas.getMatrix()) 應該會等於 canvas.concat(matrix)

因為都會Apply原本Canvas裡面的Matrix參數,於是乎就去看了一下底層的source code

 public void concat(Matrix matrix) {
     native_concat(matrix.native_instance);
 }

 public void setMatrix(Matrix matrix) {
          
matrix == null ? 0 : matrix.native_instance);
 }

看來還要追到NDK那層,不過看起來兩種設定Matrix的方式有些出入,就等未來有空再往底層看了。





2014年9月27日 星期六

StreamTokenizer

    近在實作藍牙時,碰到處理接收資料的問題,原本是用InputStream.read(byte[]),但會碰到字串切割的問題,假設原本想傳送110給App,就有可能會收到1跟10的兩個數字;

    因無法判斷何時需要斷點,直覺想到可以自定義分割符號(例如:冒號,100:110:120),如果要自己實作buffer的話又嫌太麻煩。

    最後找到Java有StringTokenizer以及StreamTokenizer就可以自動幫我分割好字串(生活變得更加美麗),有興趣的話可以參考範例

參考鏈結:
StringTokenizer  http://developer.android.com/reference/java/util/StringTokenizer.html
StreamTokenizer  http://developer.android.com/reference/java/io/StreamTokenizer.html

2014年7月16日 星期三

How to handle binary file by Parse's Cloud Code


   近在開發Side Project的時候,因為不預期有Server Team的support,所以就來玩玩Parse的Cloud Code,這個東西大概在一兩年前就有碰過一次,那個時候是上傳一些感測器的資料,如果超過某個Threshold就要寄送notification到device。

   這次的則是用在交易管理,最棒的是Stripe已經是Cloud Code的其中一個module,所以整合的過程不算太複雜;比較麻煩的事,我們需要上傳一包binary到Parse的Storage,如果由Client直接Create Data Object的話,就可以用ParseFile的物件直接搞定,該死的事繞過Cloud Code,它的Input預期是個JSON,這時候就有幾種解法:

1. 把Binary用Base64 Encode後放進JSON,但超過30MB的JSON會不會有其他悲劇發生?!
2. 直接Client端用ParseFile存檔,JSON裡面放上傳成功的URL。因為Binary沒有跟任何一筆Data Object關連,所以從後台Clean Cache的時候(可能)就會清掉。
3. 同上的Idea,但把資料放到S3。一樣很難清掉沒有意義的資料,因為存檔的動作都是由Client進行。
4. 用Pointer!Create 另外一個Table(Class),Client先Create好一筆Data後,把Object Id傳給Server做關聯。

   最後我們採用第四種做法,兼具consistance以及簡化的流程。但看了Parse的Free Plan,20GB的儲存空間,以我們的使用情境,大概1000筆訂單後就要開始付錢了:<

2014年7月7日 星期一

Retrofit : A type-safe REST client for Android and Java



    Square 雖然是做支付的公司,但也open了許多好用的library,像是OkHttp、Picasso跟Otto等等;目前公司產品內有使用的是Otto,它解決了Activity跟Fragment,或者Fragment跟Fragment之間的雙向溝通(關於Otto改天再寫別篇文章來描述使用情境),而今天要介紹的Retrofit能簡化Client跟Server間的Code。

    舉例說明,如果你要對Restful Server拿資料,首先你要開HttpClient,然後把Api的參數(POST/GET/PUT/DELETE以及Parameters)塞進去;因為Android不允許Http Connection跑在UI Thread,所以你必須在包一個AsyncTask;接著要Parsing Response Body,如果是JSON可以用內建的JOSN Library去一層一層get出來,聰明一點就會用Gson Library。對了你別忘記了Http還有很多複雜的情境,像是Response Code : 301/302的Redirect、Cache的功能、Retry的機制等等等等。

完整的程式片段可能會像這樣(別忘了,它還沒辦法handle 301/302、Cache跟Retry的機制):


    Retrofit能讓這一切簡單一些,讓您不再畏懼/厭煩對接所有Restful API,關於使用細節就直接參考官方文件。把同樣的程式用Retrofit再寫一次的結果如下:


如果有任何問題,歡迎各位一起討論。




2014年5月6日 星期二

Pull-to-Refresh on Android

    Pull-to-Refresh(PTR)的功能在iOS是原本就support的功能,而在Android上面既然要靠第三方Library(現在則否)來實現,由此可見Andorid生態系的UI原件多麼貧乏;自然而然就會有開發者去寫一個類似iOS的功能:

Android-PullToRefresh : 我們產品原本也用這個,但是碰到難以延伸的問題之後就改用別的(後面會提到),難以延伸的問題來自原件直接繼承,如果你要用在GridView,那你就必須用PullToRefreshGridView,這就會碰到如果你的GridView是客製化的(可能你會用GridViewHeader,或StickyGridHeaders,這個問題來自另外一個需求,Android的GridView沒有辦法加Header跟Footer),那這個Library就會讓你傷透腦筋,有了這個設計瓶頸,使我們不得不嘗試使用ActionBar-PullToRefresh。

ActionBar-PullToRefresh : Android為了更像Android,連PTR的行為也改得跟iOS不同,也就是Refresh的時候在ActionBar上會有一條跑馬燈在奔馳著,這套Library就是採用這種實作,自然而然程式的架構也不會跟UI元件直接耦合在一起。不過使用它必須要注意的是API的版本跟ActionBar的實作方式,它推出了三種Library:

1. actionbar-pulltorefresh:library : api 14+
2. extra-actionbarcompat-pulltorefresh : api7+. 使用support-library實作ActionBar
3. extra-actionbarshelock-pulltorefresh : api7+. 使用ActionBarshelock

這套Library採用Delegate的方式與元件互動,有興趣的話可以直接看他們的example code

mPullToRefreshLayout = (PullToRefreshLayout) view.findViewById(R.id.ptr_layout);
ActionBarPullToRefresh.from(getActivity())
                    .allChildrenArePullable()
                    .listener(this)
                    .setup(mPullToRefreshLayout);

但可惜的是該套Library已經不在維護,因為Google官方的support-library(v19.02)已經默默推出了SwipeRefreshLayout;再者它跑在Amazon Kindle機器上也會有Bug,感覺是padding算錯了,所以沒有辦法跟ActionBar貼在一起,所以最後我們會採用Google官方的版本。

SwipeRefreshLayout(API 7+):他跟ActionBar-PTR不同的地方在於Animation,上者是從左到右的跑馬燈,而它從中間往外擴的跑馬燈,而且在拖拉到一半的時候不會有提示訊息擋在ActionBar上,API使用的方式也蠻像ActionBar-PRT,但目前是第一版所以有些問題需要自己修改。

1. 無法ListView/GridView無法ScrollUp : 這個問題會發生在你包Layout的時候,如果第一個元件不是List/GridView的話就會發生。
2. 拖拉時,該頁面"一定"會彈跳 : 有些Design不預期有這種行為,但現在的API架構也無法讓你取消它。


寫到最後,才發現如果把細節寫下去可能會長到太過誇張,所以這篇文章先定位成選用不同PTR Solution的Outline,而實作及設計細節就留給其他文章當作"救援投手"了。

2014年3月4日 星期二

Bolts it!


    據前一篇Deferred&Promise的討論後,我們最後選擇了Parse發佈的Bolts。這篇大概介紹一下Bolts的實際應用方式,某些部分比較像是再把官方文件在述說一次,最後再做個總結。

Q. 什麼情況下要用Bolts?
A. 所有會卡UI Thread的事情都要,包含網路存取,檔案讀寫,複雜的運算等等

Sample Code:

Task.callInBackground(new Callable<Result>() {
     @Override
     public Result call() {
         // DO SOMETHING
         return result;
     }
});


Q. 那跟AsyncTask沒什麼差別呀?
A. 沒錯,但是Bolts可以應付更複雜的情境
情境:從網路抓一份list(約一百筆資料),並將list中的個人照片抓取下來,最後放到local資料夾。

難題:當然可以把所有事情放到一個AsyncTask裡面做完,所以整個Task時間拉很長,比較好的做法是不同的工作需求可以用不同的Executor來執行,而不同的Executor可以用不同的Policy來調整(包括ThreadPool的Size,Timeout的時間等等);而且每個Sub-Task也要擁有不同的fallback或Error Handling。

Sample Code:

Task.callInBackground(new Callable<List<User>>() {
     @Override public List<User> call() {
         return queryListFromNetwork();
     }
}, NETWORK_EXECUTOR)
.onSuccess(Continuation<List<User>, List<Image>>() {
    @Override public List<List<Image>> then(Task<List<User>> task) {
        List<Image> list = new ArrayList<Image>();
        for (User user : task.getResult()) {
             list.add(loadImage(user));
        }
        return list;
    }
}, NETWORK_EXECUTOR)
.onSuccess(Continuation<List<Image>, Integer>() {
    @Override public Integer then(Task<List< Image >> task) {
        int count = 0;
        for (Image image : task.getResult()) {
             saveToStorage(image);
             count ++;
        }
        return count;
    }
}, STORAGE_EXECUTOR)
.continueWith(Continuation<Integer, Void>() {
    @Override public void then(Task<Integer> task) {
        if (task.isFault()) {
            task.getError();
        }
        if (task.isComplete()) {
            // show success message
        }
    }
}, UI_EXECUTOR);


Q. 那是否支援等待多個Task?
A. 當然,可以使用Task.whenAll()

Sample Code

List<Task> tasks = new ArrayList<Task>();
for (int i = 0 ; i< 100 ; i ++) {
    tasks.add(Task.callInBackground(new Callable<Void>() {
      @Override public void call() {
         downloadFile();
         return null;
      }
    }));
}
Task.whenAll(tasks).continueWith(Continuation<Void, Void>() {
    @Override public void then(Task<Void> task) {
        if (task.isFault()) {
            task.getError();
        }
        if (task.isComplete()) {
            // show success message
        }
    }
}, UI_EXECUTOR);


Q 看起來那麼完美,那目前是否有些缺點?
A 當然,畢竟是v1.0.0,目前看到比較缺乏的功能:1. 無法cancel Task。2. 當使用whenAll的時候無法取得所有Sub-Task的Result。



如果還有什麼使用上或者解說上不是那麼清楚的地方請與我聯繫討論。



2014年2月17日 星期一

Kindle Fire's soft-key bar

   近APP要重新上架到Amazon的App Store,在Review時被測出一個Issue;就是在Full-Screen的Activity當置底(BOTTOM|CENTER)的DialogFragment彈出時,會被Kindle Fire的Soft-key Bar給擋住。

    原因在於Kindle Fire的Soft-key不是固定占用系統的高度,所以在Full Screen時,如果彈出的Dialog可以支援Back Key來取消的時候,它就會雞婆的把Soft-key用Overlay的方式跳出,就巧妙地擋住部分的Dialog。

原本的解法是判斷手機是否為Kindle Fire,然後決定要不要加上一個神奇的Margin-Bottom,但後來跟同事Pair-Program後,發現到DialogFragment加道Window時,並沒有繼承現在Activity的屬性(也就是全螢幕),所以才會做出如此蠢事。

最後我們捨棄的Magic Margin,而是強制將DialogFragment設成全螢幕的模式,如此該死的Soft-Key Bar就不會莫名其妙的彈跳出來。

Sample Code :

dialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);

2014年2月9日 星期日

Deferred & Promise



最近同事在解High Resolution issue的時候用到了Deferred/Promise的Design Pattern

問題是這樣子,要同時讀取及輸出N個圖片,但同時可以用M個Worker進行以節省時間,而圖片輸出的順序必須依照z-order排序,這表示圖片B輸出時必須等圖片A輸出完成。

這個問題的關鍵在於Task之間必須有Dependency的觀念,如果純用JAVA硬幹是可以用Thread Pool再加上Callable/Future實現,但針對這種問題已經有Deferred/Promise的設計概念可以使用。

簡單介紹一下D&P的概念(如上圖所示),如果Task之間有Dependency,甚至是帶入參數必須等前一個Task完成才能決定時,就非常適合使用它。

在jQuery 1.5之後已經有直接內建DeferredObject
http://api.jquery.com/category/deferred-object/

在Go的語言也是
http://golang.org/doc/effective_go.html#defer

Python也有人包library
http://twistedmatrix.com/documents/13.0.0/core/howto/defer.html

Java雖然不是內建但也有人包成library : jDeferred,當然也有Android的support
https://github.com/jdeferred/jdeferred

最近Parse也release一款類似的library : Bolts (iOS/Android supported)
https://github.com/BoltsFramework/

參考鏈結:

What are the differences between deferred promise and future in JS
http://stackoverflow.com/questions/6801283/what-are-the-differences-between-deferred-promise-and-future-in-javascript