本期內容包括: 用Mockito做RxJava的單元測試; Android開發中的命令行使用; Android 7.1的App Shortcuts; 自定義View的繪製; 用Firebase的Remote Config進行feature逐步分發; APK分析工具的使用, APK瘦身討論; RxJa... ...
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
Testing asynchronous RxJava code using Mockito
這篇文章講瞭如何用Mockito給RxJava的非同步請求代碼寫單元測試.
內容包括了:
- 如何設置Mockito的預設返回值. (通過自定義的
MockitoConfiguration
類). - 如何把非同步變為同步測試. (1.用
blockingGet()
; 2.在RxJava2中, 可以使用TestObserver
的awaitTerminalEvent()
). - AssertJ的使用.
- 測試非同步代碼. 使用Rule來替換原來的scheduler.
flatMap()
,concatMap()
,concatMapEager()
操作符的使用.- 測試Timeout.
- 測試異常和retry邏輯.
好用的工具: AssertJ
用來更方便地寫Java測試中的assert語句.
Mastering the Terminal side of Android development
作者分享了在Android開發中他是如何使用命令行的.
使用更好的命令行程式: iTerm2.
它有很多有用的features, 比如分屏, 自定義顏色, 粘貼歷史等.
on-my-zsh:
on-my-zsh內置了一個git plugin, 提供了很多aliases和功能.
zsh-autosuggestions會在你輸入的時候根據歷史提供建議.
你可以用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.
Exploring Android Nougat 7.1 App Shortcuts
這篇文章講Android 7.1推出的App Shortcuts如何實現.
The Quirks of Supporting SDK 25
作者分享了她在適配Nougat, API 25時學到的東西, 包括更換SDK版本, 圓形的啟動icon, 還有app shortcuts. (根據文中的圖標, 這個app居然是domain).
Android: draw a custom view
作者自定義了一個ViewPager的page indicator: PageIndicatorView.
這篇文章講述瞭如何自定義View, 首先是View的生命周期, 然後是具體如何實現, 如何避免一些常見的錯誤, 最後是如何添加View的動畫.
各個生命周期中應該乾的事情:
- 構造函數中: 解析自定義屬性.
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
, 它可以讓你動畫任何值.
How to Stage Rollout Features using Firebase Remote Config
Staged Rollout是Google Play Store的一個feature. 讓你可以慢慢地把新版App發佈給一部分用戶, 並逐漸增大比例. 使用Firebase Remote Config, 我們可以做的更多, 我們可以控制某個feature的發佈.
Making the most of the APK analyzer
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), 類混淆等問題.
Rxify
: The Anti Cache-then-Network OR Network-then-Cache Problem
用RxJava處理網路請求和緩存.
- 如果先使用Cache, 沒有緩存的時候再進行網路請求. -> 用
.concatWith()
和.take(1)
. - 如果優先取網路最新數據, 沒網的時候才用緩存數據. ->
.onErrorReturn()
.
Your presenters don’t need all those lifecycle events
作者認為在Presenter中放入太多生命周期的方法不太好, 他覺得最基本的只需要這兩個方法:
public interface Presenter {
void onViewAttached(MVPView view);
void onViewDetached();
}
當然當你需要更多的時候可以加入更多, 但是我們不應該每個生命周期方法都加進去.
How to send notifications using Android Firebase
使用Firebase Messaging如何發送push notification.
RxRecipes: Wrap your way to Rx
使用.fromCallable()
來把一個同步方法包裝成一個Observable.
並比較了和.just()
的區別. (.just()
發射的東西在創建的時候就確定了, 而.fromCallable()
是在subscribe的時候確定的.)
Diving deeper into the Java transient modifier
transient
修飾符加在欄位上時, 在對象被序列化的時候, 這個欄位將被排除在外, 反序列化時這個欄位將被初始化一個預設值.
可能的使用場景:
- 實現了Serializable的User對象中的password欄位.
- 一個Serializable的類中的某個欄位是通過其他欄位推導或派生出來的, 這些派生的欄位沒有必要被序列化, 於是把它們標記為
transient
.
註意transient和static是不能並存的, 因為static預設是transient的.
LIBRARIES & CODE
Tinker
騰訊的熱補丁(hot-fix)解決方案, 支持不重新安裝app的dex, library和資源更新.
Android-Debug-Database
在瀏覽器里看應用的資料庫和shared preferences.
blurkit-android
實時模糊佈局. 像iOS一樣.