天天看點

Android Weekly Notes Issue #233

本期内容包括: 用Mockito做RxJava的單元測試; Android開發中的指令行使用; Android 7.1的App Shortcuts; 自定義View的繪制; 用Firebase的Remote Config進行feature逐漸分發; APK分析工具的使用, APK瘦身讨論; RxJava處理網絡請求和緩存; presenter的設計; 用Firebase發送push notification; transient關鍵字的使用等.

November 27th, 2016

Android Weekly Issue #233

這篇文章講了如何用Mockito給RxJava的異步請求代碼寫單元測試.

内容包括了:

如何設定Mockito的預設傳回值. (通過自定義的<code>MockitoConfiguration</code>類).

如何把異步變為同步測試. (1.用<code>blockingGet()</code>; 2.在RxJava2中, 可以使用<code>TestObserver</code>的<code>awaitTerminalEvent()</code>).

AssertJ的使用.

測試異步代碼. 使用Rule來替換原來的scheduler.

<code>flatMap()</code>, <code>concatMap()</code>, <code>concatMapEager()</code>操作符的使用.

測試Timeout.

測試異常和retry邏輯.

好用的工具: AssertJ

用來更友善地寫Java測試中的assert語句.

作者分享了在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, 一句指令就可以:

Build faster, build offline

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

在Android Studio中也可以進行設定.

在<code>Settings -&gt; Build, Execution, Deployment -&gt; Build tools -&gt; Gradle</code>中勾選<code>Offline work</code>即可.

alfi

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

gradle tasks shortcuts

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

iDD for installDevelopmentDebug

aDD for assembleDevelopmentDebug

cC for connectedCheck

Android Rocket Launcher

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

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

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

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

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

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

這篇文章講述了如何自定義View, 首先是View的生命周期, 然後是具體如何實作, 如何避免一些常見的錯誤, 最後是如何添加View的動畫.

Android Weekly Notes Issue #233

各個生命周期中應該幹的事情:

構造函數中: 解析自定義屬性.

<code>onAttachedToWindow()</code>中: 可以發現同一布局中相關的其他View, 其id是上一步通過自定義屬性傳入的.

<code>onMeasure()</code>: 自定義View尺寸相關, 當覆寫這個方法時, 最後要調用<code>setMeasuredDimension(int width, int height)</code>.

<code>onLayout()</code>: 一般這個方法是給ViewGroup的child指定位置和尺寸的, 對于自定義View來說, 沒有child就沒有必要覆寫這個方法.

<code>onDraw()</code>: 這裡是畫東西的地方. 用canvas和Paint結合繪制. 需要注意的是<code>onDraw()</code>會被多次調用, 當你有一些變化, 滾動滑動等, 都會重繪, 是以這個方法中不要建立新對象.

View更新

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

<code>invalidate()</code>: 隻是重新繪制, 調用<code>onDraw()</code>方法.

<code>requestLayout()</code>: 将會從<code>onMeasure()</code>開始, 可能會改變尺寸, 然後根據新尺寸重新繪制.

Animation

自定義View的動畫是一幀幀進行的, 這就意味着你每一步都要調用<code>invalidate()</code>來畫它.

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

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

Android Studio中Build菜單有一項是<code>Analyze APK...</code>, 這是一個很有用的功能.

<code>Raw File Size</code>是apk在磁盤上的大小.

<code>Download size</code>是估計下載下傳你的應用所需要的資料流量大小, 考慮到了Play Store的壓縮.

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

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

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

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

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

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

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

用RxJava處理網絡請求和緩存.

如果先使用Cache, 沒有緩存的時候再進行網絡請求. -&gt; 用<code>.concatWith()</code>和<code>.take(1)</code>.

如果優先取網絡最新資料, 沒網的時候才用緩存資料. -&gt; <code>.onErrorReturn()</code>.

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

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

使用Firebase Messaging如何發送push notification.

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

并比較了和<code>.just()</code>的差別. (<code>.just()</code>發射的東西在建立的時候就确定了, 而<code>.fromCallable()</code>是在subscribe的時候确定的.)

<code>transient</code>修飾符加在字段上時, 在對象被序列化的時候, 這個字段将被排除在外, 反序列化時這個字段将被初始化一個預設值.

可能的使用場景:

實作了Serializable的User對象中的password字段.

一個Serializable的類中的某個字段是通過其他字段推導或派生出來的, 這些派生的字段沒有必要被序列化, 于是把它們标記為<code>transient</code>.

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

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

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

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

作者: 聖騎士Wind

出處: 部落格園: 聖騎士Wind

Github: https://github.com/mengdd

微信公衆号: 聖騎士Wind

Android Weekly Notes Issue #233