December 11th, 2016
Android Weekly Issue #235
本期內容包括: 開發一個自定義View併發布爲開源庫的完整流程介紹; 用AnimatedVectorDrawable
實現的動畫; 什麼樣的程序是可測試的; DownloadManager
介紹; Okhttp的重試; Android 7取消了file://
; Android Studio即將推出的build cache功能; 支持離線模式的app構架; 如何寫自定義的lint規則; Epoxy, 一個處理複雜RecyclerView屏的庫; FragmentPagerAdapter
和FragmentStatePagerAdapter
的比較等.html
做者開發了一個環形的SeekBar, 並把它做爲一個庫發佈到了JCenter.java
做者首先講了自定義View的實現:
首先是關於View生命週期的介紹, 在寫自定義View的時候有幾個關鍵的生命週期回調須要處理:
android
做者實現的幾個關鍵步驟講解:git
onMeasure()
中控制尺寸.onDraw()
中繪製: 避免在onDraw()
中分配內存; 用invalidate()
方法來激發重繪.onTouchEvent()
處理用戶手勢. 在他的環形SeekBar的實現裏, 這裏涉及到了點擊座標到角度的轉換.將自定義View庫開源到Github:
開源到Github有個好的README很重要, 這裏有幾個tips:github
發佈庫:api
用AnimatedVectorDrawable
實現的一個很fancy的位置標誌動畫.android-studio
若是程序的架構不適合測試, 那麼硬要寫一些測試極可能就會面臨這樣的局面: 要麼就是發現無法寫測試, 要麼就是爲了寫測試而破壞了代碼, 作了一些奇怪的事情.緩存
那麼究竟是什麼樣的程序纔是適合寫測試, 或者是可測試的呢?cookie
有一個有趣的定義是seam(接縫), 在接縫處你能夠改變程序的行爲, 而不用編輯當前程序. 若是程序沒有接縫, 你將沒法設置測試的初始條件和驗證測試結果.網絡
本文中舉了一個實際的例子, 開始的時候程序沒有seam, 因此致使沒法測試, 後來把靜態方法改成實例的方法以後, 咱們就能夠經過Mockito來模擬行爲, 設置條件, 最後經過驗證某一方法的調用與否來進行驗證.
用DownloadManager
來處理下載.
首先它在設備上有本身的UI, 還有notification, 還有Downloads app能讓用戶管理下載文件.
咱們能夠查詢到文件的一些信息, 好比MIME type, 文件尺寸, 下載狀態等.
咱們還能夠用getUriForDownloadedFile()
方法來獲取一個URI, 配合MIME type, 發送Intent, 來打開一個相關的查看程序.
關於儲存文件的合適地點:
setDestinationInExternalFilesDir()
.WRITE_EXTERNAL_STORAGE
權限. setDestinationInExternalPublicDir()
.在網路較慢或不穩定的時候, OkHttp有可能會重複發送請求, 直到成功.
這個重試的邏輯是經過RetryAndFollowUpInterceptor.java實現的.
那麼, 咱們能夠關掉這個重試行爲嗎? 有一些issues就在討論這個問題: Issue # 1043. 後來有兩個pull requests: PR #1259和PR #2479改進了這個問題, 減小(但並無消除)了沒必要要的retry請求.
全局關閉重試行爲: OkHttpClient.Builder .retryOnConnectionFailure()
設置爲false. 可是注意這樣是很粗暴並具備破壞性的, 消除了retry邏輯帶來的好處:
解決真正的問題: 關閉靜默重試在某些情形下有幫助, 可是其實它隱藏了真正的問題, 就是你的API是不是冪等的idempotent. server端能夠根據客戶端的GUID來檢測重複, 這樣server就不會屢次執行操做, 會通知發送者.
Android N (Nougat, API 24)開始, 再也不容許發送file://
的Intent, 將會直接拋出FileUriExposedException
異常.
因此當你把targetSdkVersion
改成24以後, 你必需要確保你修復了這些問題再發布.
解決方案是什麼呢? 用content://
, 結合FileProvider
:
首先在manifest裏面聲明:
<provider android:name="android.support.v4.content.FileProvider" android:authorities="${applicationId}.provider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/provider_paths"/> </provider>
而後在res\xml\provider_paths.xml
文件裏指明路徑:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path name="external_files" path="."/> </paths>
最後, 把
Uri photoURI = Uri.fromFile(createImageFile());
改成
Uri photoURI = FileProvider.getUriForFile(MainActivity.this, BuildConfig.APPLICATION_ID + ".provider", createImageFile());
而後放在Intent裏發送就行了.
注意, 若是你的targetSdkVersion
尚未更新到24, 那麼即使是在Nougat的手機上file://
也仍然是能正常使用的.
Android Studio當前的最新版是2.3 Canary 2. 有一些新的改進, 可是其中最吸引人的是這個build cache. 它會使你的clean build更快.
本文後面解析了build cache的工做原理.
一個好的應用應該在網絡很差甚至離線的時候仍然可使用, 咱們應該作些什麼呢?
如何建立自定義的lint規則.
事情的由來是做者發現了一個死循環調用, 而後他想作一個什麼標記以防之後其餘人會犯一樣的錯誤.
而後他想到的是@Nullable註解, 的檢查, 實質是依靠lint來實現的.
因而他本身寫了一個自定義的lint規則, 來提示使用用他的註解@CarefulNow
標記的方法時應當注意.
詳細的實現方式請看原文.
epoxy是一個Android庫, 用來處理複雜的RecyclerView屏. 本文介紹了它在項目中實際的使用.
可能有不少Android開發者對於
FragmentPagerAdapter和FragmentStatePagerAdapter的區別不是太清楚或根本不知道, 本文做者就具體介紹了兩者的不一樣.
基本不一樣
FragmentPagerAdapter
適用於項目個數肯定的情形.
爲何呢? 由於一旦fragment的實例被建立, 它永遠也不會從FragmentManager
中移除, 直到Activity被銷燬.
當Fragment不見的時候, 僅僅是onDestroyView()
被調用, 當fragment再次回來時, 再調用onCreateView()
.
FragmentStatePagerAdapter
當fragment的實例不可達的時候, 實例就會當即從FragmentManager
移除. 被移除的fragment實例的狀態由FragmentStatePagerAdapter
保存, 當你再次回到該項的時候, fragment會重建新實例, 而且狀態被恢復. 因此這種adapter適用於項目個數不肯定或的狀況.
因此使用FragmentPagerAdapter
的時候須要注意內存問題.
notifyDatasetChanged()的問題.
notifyDataSetChanged()
是用來處理數據集變化的狀況, 好比一些項目增刪的狀況. 這個方法不是用來刷新當前顯示的Fragment或其中的Views的.
文章中還有一些關於數據改變實現以及現有issue的討論. 爲了解決issue做者還發布了一個庫UpdatableFragmentStatePagerAdapter.
一個quick settings tile來開啓"Don't keep activities".
一個波形的loading圖, 水面上漲表明loading程度.
Simple MVWhatever for Android.
一個處理複雜的RecyclerView屏的庫.
錄屏腳本.