1. 程式人生 > >Android Weekly Notes Issue #233

Android Weekly Notes Issue #233

Android Weekly Issue #233

November 27th, 2016
Android Weekly Issue #233
本期內容包括: 用Mockito做RxJava的單元測試; Android開發中的命令列使用; Android 7.1的App Shortcuts; 自定義View的繪製; 用Firebase的Remote Config進行feature逐步分發; APK分析工具的使用, APK瘦身討論; RxJava處理網路請求和快取; presenter的設計; 用Firebase傳送push notification; transient關鍵字的使用等.

ARTICLES & TUTORIALS

這篇文章講了如何用Mockito給RxJava的非同步請求程式碼寫單元測試.
內容包括了:

  • 如何設定Mockito的預設返回值. (通過自定義的MockitoConfiguration類).
  • 如何把非同步變為同步測試. (1.用blockingGet(); 2.在RxJava2中, 可以使用TestObserverawaitTerminalEvent()).
  • 測試非同步程式碼. 使用Rule來替換原來的scheduler.
  • flatMap(), concatMap(), concatMapEager()操作符的使用.
  • 測試Timeout.
  • 測試異常和retry邏輯.

好用的工具:

AssertJ
用來更方便地寫Java測試中的assert語句.

作者分享了在Android開發中他是如何使用命令列的.

使用更好的命令列程式: iTerm2.
它有很多有用的features, 比如分屏, 自定義顏色, 貼上歷史等.

on-my-zsh:

你可以用Ctrl + R在命令歷史中進行逆向智慧搜尋(Reverse intelligent search). 你開始輸入這個命令, 命令列會在歷史中尋找並自動補全. 你可以按Enter來執行這個命令, 或者左右箭頭來編輯命令, 或者繼續按Ctrl + R在其他可能的命令中尋找.

dryrun

如果你在github上看到一個程式, 想要執行一下看看, 你不必再把它下載下來, 匯入Android Studio了.

你只需要用dryrun, 一句命令就可以:

dryrun REMOTE_GIT_URL

Build faster, build offline

在build的時候使用--offline可以讓所有依賴都使用快取版本, 不再進行網路請求, 從而加快執行速度.

./gradlew assembleDevelopDebug --offline
./gradlew test --offline

在Android Studio中也可以進行設定.
Settings -> Build, Execution, Deployment -> Build tools -> Gradle中勾選Offline work即可.

alfi
alfi是一個工具, 裝了這個工具之後, 用一行命令就可以查到第三方庫的依賴語句, 然後你就可以把它拷貝貼上到build.gradle中去了.

gradle tasks shortcuts
gradle的task有縮寫版的, 比如:

  • iDD for installDevelopmentDebug
  • aDD for assembleDevelopmentDebug
  • cC for connectedCheck

Android Rocket Launcher
Android Rocket Launcher增加新的tasks, 在命令列啟動應用.

直接在console輸出單元測試結果:

android {
  ...
  testOptions.unitTests.all {
    testLogging {
      events 'passed', 'skipped', 'failed', 'standardOut', 'standardError'
      outputs.upToDateWhen { false }
      showStandardStreams = true
    }
  }
}

這個工具pidcat可以指定包名顯示log.

這篇文章講Android 7.1推出的App Shortcuts如何實現.

作者分享了她在適配Nougat, API 25時學到的東西, 包括更換SDK版本, 圓形的啟動icon, 還有app shortcuts. (根據文中的圖示, 這個app居然是domain).

作者自定義了一個ViewPager的page indicator: PageIndicatorView.

這篇文章講述瞭如何自定義View, 首先是View的生命週期, 然後是具體如何實現, 如何避免一些常見的錯誤, 最後是如何新增View的動畫.
view lifecycle

各個生命週期中應該乾的事情:

  • 建構函式中: 解析自定義屬性.
  • onAttachedToWindow()中: 可以發現同一佈局中相關的其他View, 其id是上一步通過自定義屬性傳入的.
  • onMeasure(): 自定義View尺寸相關, 當覆蓋這個方法時, 最後要呼叫setMeasuredDimension(int width, int height).
  • onLayout(): 一般這個方法是給ViewGroup的child指定位置和尺寸的, 對於自定義View來說, 沒有child就沒有必要覆蓋這個方法.
  • onDraw(): 這裡是畫東西的地方. 用canvas和Paint結合繪製. 需要注意的是onDraw()會被多次呼叫, 當你有一些變化, 滾動滑動等, 都會重繪, 所以這個方法中不要建立新物件.

View更新
有兩個方法可以讓View重繪:

  • invalidate(): 只是重新繪製, 呼叫onDraw()方法.
  • requestLayout(): 將會從onMeasure()開始, 可能會改變尺寸, 然後根據新尺寸重新繪製.

Animation
自定義View的動畫是一幀幀進行的, 這就意味著你每一步都要呼叫invalidate()來畫它.

在自定義View中你的動畫好助手是ValueAnimator, 它可以讓你動畫任何值.

Staged Rollout是Google Play Store的一個feature. 讓你可以慢慢地把新版App釋出給一部分使用者, 並逐漸增大比例. 使用Firebase Remote Config, 我們可以做的更多, 我們可以控制某個feature的釋出.

Android Studio中Build選單有一項是Analyze APK..., 這是一個很有用的功能.

Raw File Size是apk在磁碟上的大小.
Download size是估計下載你的應用所需要的資料流量大小, 考慮到了Play Store的壓縮.

檔案和資料夾是按照大小降序排列的. 這對於Apk瘦身來說很有用, 很容易發現最佔地方的原因.

比如作者發現了一些png很佔地方, 於是就用PSD support in the Vector Asset import tool把它們轉成了VectorDrawable, 後向相容用VectorDrawableCompat.

有一些沒有壓縮的WAV可以轉成OGG.

在lib/裡面, 發現它們要支援的三個ABI: x86, armeabi-v7a, armeabi, 解決的辦法就是利用apk拆分, 針對每一個ABI有一個不同的版本.

還有一個優化是把android:extractNativeLibs 屬性設定為false, 這樣系統就不會把.so檔案在安裝的時候從apk中拷貝到檔案系統了. 這樣應用的增量更新也會小一點.

這個功能有一個"Compare with"按鈕, 利用它你可以比較兩個apk的改變.

可以通過檢視DEX檔案來檢視方法數限制 (Referenced Methods), 類混淆等問題.

用RxJava處理網路請求和快取.

  • 如果先使用Cache, 沒有快取的時候再進行網路請求. -> 用.concatWith().take(1).
  • 如果優先取網路最新資料, 沒網的時候才用快取資料. -> .onErrorReturn().

作者認為在Presenter中放入太多生命週期的方法不太好, 他覺得最基本的只需要這兩個方法:

public interface Presenter {
  void onViewAttached(MVPView view); 
  void onViewDetached();
}

當然當你需要更多的時候可以加入更多, 但是我們不應該每個生命週期方法都加進去.

使用Firebase Messaging如何傳送push notification.

使用.fromCallable()來把一個同步方法包裝成一個Observable.

並比較了和.just()的區別. (.just()發射的東西在建立的時候就確定了, 而.fromCallable()是在subscribe的時候確定的.)

transient修飾符加在欄位上時, 在物件被序列化的時候, 這個欄位將被排除在外, 反序列化時這個欄位將被初始化一個預設值.

可能的使用場景:

  • 實現了Serializable的User物件中的password欄位.
  • 一個Serializable的類中的某個欄位是通過其他欄位推導或派生出來的, 這些派生的欄位沒有必要被序列化, 於是把它們標記為transient.

注意transient和static是不能並存的, 因為static預設是transient的.

LIBRARIES & CODE

騰訊的熱補丁(hot-fix)解決方案, 支援不重新安裝app的dex, library和資源更新.

在瀏覽器裡看應用的資料庫和shared preferences.

實時模糊佈局. 像iOS一樣.