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年6月1日 星期日
Dart : The New Platform for Scalable Web App Engineering
Google的風格就是,當某種語言/工具無法滿足需求時,就會自己創造一個全新的,Dart也是其中一個產物。
Dart的目的是要取代Javascript,因為它實在是太多問題了(Firefox : 哪會),但目前除了Chrome以外,沒人願意把DartVM綁在自己的Browser裡,不過目前Dart Code還是可以轉成Javascript(轉換後不預期你做任何修改),執行在其他的瀏覽器上面(據說Performance也比原本的Javascript Native來的好),如此創新的作法還真的讓人躍躍欲試,但是,想到許多原本用的很開心的Javascript library都要等別人包成Dart的Plugin才能使用。
基於最後的結論,我還是緩緩先。
Reference:
Wiki : http://zh.wikipedia.org/wiki/Dart
https://www.dartlang.org/
Dart的目的是要取代Javascript,因為它實在是太多問題了(Firefox : 哪會),但目前除了Chrome以外,沒人願意把DartVM綁在自己的Browser裡,不過目前Dart Code還是可以轉成Javascript(轉換後不預期你做任何修改),執行在其他的瀏覽器上面(據說Performance也比原本的Javascript Native來的好),如此創新的作法還真的讓人躍躍欲試,但是,想到許多原本用的很開心的Javascript library都要等別人包成Dart的Plugin才能使用。
基於最後的結論,我還是緩緩先。
Reference:
Wiki : http://zh.wikipedia.org/wiki/Dart
標籤:
app,
fae,
javascript,
js,
web
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年4月29日 星期二
The future of JVM : JRuby
昨晚公司邀請了JRuby的Contributor : Charles Oliver Nutter來談談JRuby,也談談未來JVM會的長相。JRuby的目的是讓原本只能活在JVM的Java Code,忽然可以跟世界外的語言有所互動,Ruby是其中之一,當然還有Python(Jython),為了要辦到這件事情有許多問題需要解決。
他提到第一點,Bootstrap Time,他用了JVM可以微調的Flag,加上Pre-load JVM的技術(Drip/NailGun/還有一個忘了),讓執行時間跟跑原本的Ruby環境差不多(個人懷疑Runtim memory可能大上好幾倍)。
第二點是Native Code,原本的世界裡,如果Java要呼叫Native的Code只能透過JNI(例如拿process ID),他本人是非常討厭JNI,除了寫起來吃力不討好之外,也提高的平台相依性(跟JAVA的初衷Write one, Run anywhere有所抵觸),他提到新的玩意叫做Java Native Runtime(JNR)也能辦到相同的事情,除了Interface比較簡潔外,也有龐大的community再幫你解決不同平台上所需要解決的Porting問題,其目的為把所有POSIX上支援的function都有一份Java對應的實作(不過目前還沒完全支援)。
最後他提到JAVA 7之後support的invokedynamic指令,從bytecode等級支援新的語法來提升動態語言的效能。他也提到說每個Engineer都會想要創造自己的程式語言,但礙于並非對Compiler有所專精,而且可能要寫非常多底層的Code來Optimize performance,所以有一個新的架構可以滿足/解決我們的問題,它是Graal,概念有點像是C跟LLVM,而JAVA跟Graal,實際運作是所有的Java Code不會直接Compile成Bytecode,而是Graal Representation,然後再透過Graal的IR做最佳化之後直接Run再Native Code上面;有了Graal後再搭配Truffle,它能夠讓你自己撰寫IR去Optimize你的Code(當然也可以寫JAVA),如此一來,你就可以打造一個完全屬於你的語言了(但還是跑在JVM上面)
備註:本篇文章是根據昨晚聽完簡報後所撰寫,可能技術細節的描述有所錯誤,麻煩請多多指教。
2014年3月31日 星期一
4am.tw + parallax scrolling
今天看完盧廣仲演唱會後異常熱血,喝了點小酒開始把之前hackthon的project重新從github checkout下來;這次想幫4am.tw用parallax scrolling的library(skollr)寫了另外一個版本. 資料全部來自於原本的網站(不知是否會有授權問題?);而source code(在這)。BTW因為它架在Heroku所以如果太久沒人用會呈現睡眠的狀態。
目前沒有做到很完美~歡迎大家指教。
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。
如果還有什麼使用上或者解說上不是那麼清楚的地方請與我聯繫討論。
訂閱:
文章 (Atom)



