原文地址:http://blog.joanzapata.com/robust-and-readable-part-2-introducing-async-service/
健壯且可讀的安卓架構(二)
一、基礎用法
@AsyncService
public class UserService {
public User getUser(String name) {
return ...;
}
}
當你在activity裏面注入這個UserService的時候,你可以在任何線程裏面回調getUser()這個方法,它會立即返回null並開始異步執行,結果會以一個消息的形式返回,你可以通過構造一個帶有合適的參數方法拿到這個結果。public class MyActivity extends Activity {
@InjectService public UserService userService;
public void onCreate(Bundle savedInstanceState){
// Runs injections and detect @OnMessage callback methods
AsyncService.inject(this);
// Starts method asynchronously (never catch the result here, would be null)
userService.getUser("Joan");
}
// Callback method for getUser
@OnMessage void onUser(User e) {
// Runs on UI thread.
}
}
注意:
調用緩存:
@Background(serial = CACHE)
public void getUser() {
postIfPresent(KEY_USER, UserFetchedEvent.class);
getUserAsync();
}
@Background(serial = NETWORK)
private void getUserAsync() {
cacheThenPost(KEY_USER, new UserFetchedEvent(candyshopApi.fetchUser()));
}
這樣,依舊需要很多個引用代碼去寫每個請求,AsyncService有這樣一個註釋:@CacheThenCall
public User getUser(){
return ...;
}
這樣很簡潔,對嗎?它依舊以相同的方式在後臺工作。@CacheThenCall(key="UserService.getUser({name})")
public User getUser(String name){
return ...;
}
一般來說,緩存鍵值的默認值形式爲"<Class.name>.<MethodName>({arg1},{arg2},...)",所以在這個地方我們實際上並不需要去標記它。
錯誤管理
@AsyncService(errorMapper = StatusCodeMapper.class)
@ErrorManagement({
@Mapping(on = 0, send = NoNetworkError.class),
@Mapping(on = 500, send = ServerInternalError.class),
@Mapping(on = 503, send = ServerMaintenanceError.class),
...})
public class UserService {
@ErrorManagement({
@Mapping(on = 404, send = UserNotFoundError.class),
...})
public User getUser(String username){
return ...;
}
}
public class StatusCodeMapper implements ErrorMapper {
@Override
public int mapError(Throwable throwable) {
if (throwable instanceof HttpStatusCodeException)
return ((HttpStatusCodeException) throwable).getStatusCode().value();
if (isConnectivityError(throwable))
return 0;
return SKIP;
}
}
如果返回的是SKIP,那麼意味着這個錯誤沒有捕獲,那麼它會發送到UncaughtExceptionHandler(這個類是全局異常捕獲類,之前寫的文章裏有說明),如果沒聽過這個類,這個類就是所有你未捕獲的錯誤所去的地方。一些錯誤報告工具例如:ACRA\Crashlytic等,捕獲錯誤並報告。@OnMessage
void onError(UserNotFoundError e){
Toast.makeText(this, "User does not exist.", LENGTH_LONG).show();
}
當錯誤發生在getUser(String name)方法時,你可以更進一步的捕獲到用戶名。這樣,你可以定義一個參數在錯誤信息中:public class UserNotFoundError {
public UserNotFound(@ThrowerParam("username") String username){
this.username = username;
}
...
那麼現在你可以更加準確的展示信息:@OnMessage
void onError(UserNotFoundError e){
Toast.makeText(this, String.format("User %s does not exist.", e.getUsername()), LENGTH_LONG).show();
}