Android Weekly Notes Issue #255

weixin_34128411發表於2017-05-03

Android Weekly Issue #255

April 30th, 2017
Android Weekly Issue #255
本期內容包括: 一種在RxJava中顯示loading/content/error的好的處理方法; Android O中的一些隱藏寶藏; Uber app的immutable的資料升級; MVP模式下, 不要再做view != null的判斷了; 用Dagger2實現的依賴注入; 遷移應用到Kotlin; 如何把Gradle外掛從Groovy遷移到Kotlin; Activity中的靜態start方法使用; Firebase的實時資料庫使用.

ARTICLES & TUTORIALS

LCE: Modeling Data Loading in RxJava

作者介紹了一種方法, 用RxJava來處理顯示loading/內容/錯誤的邏輯.

核心思想是中這個結構把資料包一層:

// Lce -> Loading / Content / Error
class Lce<T> {
    public static <T> Lce<T> data(T data) {
        // implementation
    }

    public static <T> Lce<T> error(Throwable error) {
        // implementation
    }

    public static <T> Lce<T> loading() {
        // implementation
    }

    boolean isLoading();

    boolean hasError();

    Throwable getError();

    T getData();
}

然後實際處理的程式碼就變成了這樣:

  repository.getDataEventStream().subscribe({ event ->
    if (event.isLoading) {
      view.showLoading(true)
    } else if (event.hasError()) {
      view.showError(event.getError())
    } else {
      view.showData(event.getData())
    } 
  })

怎麼構建這個Observable呢:

Observable<Lce<Data>> getDataEventStream() {
  return api.getData()
    .map(data -> Lce.data(data))
    .startWith(Lce.loading())
    .onErrorReturn(e -> Lce.error(e))
}

更多構建方法見原文.

Hidden Gems of Android O

作者仔細看了Android O的API Diff, 然後發現了一些隱藏的寶藏拿出來分享.

  • Storage Access Framework的改進.
  • RecoverableSecurityException.
  • SharedPreferences支援更換底層實現.
  • SmsManager.createAppSpecificSmsToken()提供的更好的簡訊驗證流.
  • 鎖屏情況下的顯示處理: Keyguard.dismissKeyguard().
  • 全屏Activity的旋轉處理.

Engineering Stability in Migrations

Uber的資料類生成及遷移到Immutable Collections的過程.

Don’t put view != null checks in your Presenters

如果你使用了MVP模式, 並且你的presenter在configuration變化時是一直存在的, 那麼你的presenter至少會有下面兩個方法:

void attachView(View)
void detachView()

這樣的話你的getView()方法應該被標記為@Nullable, 然後你就需要在很多地方做null判斷, 即便有些地方你100%地肯定View肯定不為null.

Presenter的方法直接從View中被呼叫

比如那些View中UI控制元件點選導致的呼叫.

加個view != null的判斷有一個缺點就是如果attach時出現了問題, 這時使用者點選了按鈕卻沒有反應, 這個錯誤會被忽略和隱藏起來. 在這種View應該存在的情形下, 如果得到了null, 應該及時丟擲異常發現錯誤.

It’s always a bad sign when the else branch is missing.

解決方案: 加個@NonNull View getViewOrThrow()方法:

@Nullable
public MyView getView() {...} 

@NonNull
public MyView getViewOrThrow() {
    final MyView view = getView();
    if (view == null) {
        throw new IllegalStateException("view not attached");
    }
    return view;
}

在Presenter中非同步呼叫View

很多時候我們需要非同步呼叫View的方法, 這時候我們就不能用getViewOrThrow()了, 因為View被detach是一種合理的情況.

這時候我們如果加個if (view != null)是可以解決這個問題的, 但是卻是一個錯誤的選擇. 因為else分支的缺失, 使用者可能錯過了server返回的結果, 然後永遠地等下去.

一個比較好的解決方案就是ThirtyInch, 它有一個方法叫sendToView(ViewAction), 它會推遲ViewAction的執行, 到View再次被attach的時候執行. 如果View已經處於attached的狀態, 那麼就立即執行.

一個例子:

public class MyPresenter extends TiPresenter<MyView> {

    public void onSubmitLogin(final Credentials credentials) {
        mLoginService.login(credentials).subscribe(
                success -> {
                    sendToView(view -> view.close());
                },
                error -> {
                    sendToView(view -> view.showError(error));
                });
    }
}

注意請不要過度使用sendToView().

如果你用MVI模式, 維護一個ViewModel, 在變化的時候渲染到View, 同樣也可以刪掉view != null的判斷. 見My take on Model View Intent (MVI) — Part 1: State Renderer.

Optional和WeakReference

這篇文章中用了view == null作為View被detached了的依據. 如果你使用了其他的包裝, 比如WeakReference或者Optional, 你雖然不用null判斷了但是並不代表你解決了問題, 你需要做其他的判斷並且lint不能幫你做提示了.

結論

你並不需要if (view != null)檢查:

  • 當你確定View是attached時, 使用getViewOrThrow().
  • 當View可能會是detached時, 使用sendToView(ViewAction), 來支援else的處理.

Dependency Injection in Android with Dagger 2

一個用了Retrofit和MVP模式的應用, 用Dagger2做依賴注入的例子.

How we made Basecamp 3’s Android app 100% Kotlin

作者他們如何把應用改為用Kotlin.

Migrate a Gradle Plugin from Groovy to Kotlin

如何把一個用Groovy寫的Gradle外掛轉化成Kotlin寫的.

Object Oriented Tricks: #4 Starter Pattern

在Activity中定義一個靜態的start()方法, 把需要放在intent中的引數都當做方法引數傳進來.

Android Studio對此有一個內建的模板, 你只要輸入starter, 按回車就可以生成這個方法.

Using Firebase as a Real Time System

Firebase的Real Time Database.
資料庫儲存的資訊以NoSQL的形式放在Google Cloud上.

三個主要的優點: 實時,離線處理, 自動同步.

文中展示了基本的用法.

之後提供了實時資料庫的幾種使用思路:

LIBRARIES & CODE

Bubble-Picker

氣泡選擇器.

UltimateAndroidReference

Android資源收集, 包括庫, 開源專案, 書籍部落格等等.

litho-picasso

為Litho寫的picasso庫.

相關文章