Android Weekly Notes Issue #220

来源:http://www.cnblogs.com/mengdd/archive/2016/09/01/5829870.html
-Advertisement-
Play Games

Android Weekly Issue #220, 中文筆記. ...


Android Weekly Issue #220

August 28th, 2016
Android Weekly Issue #220

ARTICLES & TUTORIALS

Manage dependencies versions with gradle extra properties

依賴管理的小Tip: 把依賴的版本號作為變數管理.
改造之後, build.gradle文件變成這樣:

apply plugin: 'com.android.application'
android {
    ...
}
...

ext {
    supportLibraryVersion = '23.4.0'
    playServicesVersion = '9.2.1'
}

dependencies {
    // support libraries
    compile "com.android.support:appcompat-v7:$supportLibraryVersion"
    compile "com.android.support:design:$supportLibraryVersion"
    compile "com.android.support:percent:$supportLibraryVersion"
    compile "com.android.support:cardview-v7:$supportLibraryVersion"
    compile "com.android.support:gridlayout-v7:$supportLibraryVersion"

    //play services
    compile "com.google.android.gms:play-services-location:$playServicesVersion"
    compile "com.google.android.gms:play-services-gcm:$playServicesVersion"

    // other dependencies
    ...
}

定義了版本號變數, 原來hardcode時的單引號變成了雙引號, 然後用$符號取變數值.

上面這個是app module裡面使用的例子, 如果你的應用有多個module怎麼辦呢?
當然一種辦法是每個module里定義一組版本號變數, 更方便的辦法是在項目工程總目錄的build.gradle文件里定義變數.
可以在工程的build文件里寫

ext {
    // sdk and tools
    minSdkVersion = 14
    targetSdkVersion = 23
    compileSdkVersion = 23
    buildToolsVersion = '23.0.2'

    // dependencies versions
    supportLibraryVersion = '23.4.0'
    playServicesVersion = '9.2.1'
}

也可以這樣定義:

project.ext.supportLibVersion = '24.0.0'

使用的時候可以這樣取值: $rootProject.supportLibraryVersion.
也可以省略前面的rootProject, 直接取$supportLibraryVersion

Android CI with Docker

作者講了他怎麼用Docker搭建CI.

  1. 環境:
    首先, CI需要Android環境(JDK 7&8, Android SDK, Gradle, Release keychain, google-services.json, etc).
    裝了這些環境之後, 需要保證他們在每一個CI實例上都是同步更新的.
    用了Docker之後, 更新環境的步驟變為:
    更新你的Dockerfile -> Push到版本管理系統 -> CI會build新的image, 然後push到docker registry.

  2. Build:
    docker run -v ./app:/opt/app docker-ci-android:latest gradle assembleRelease

  3. Test:
    有兩種測試, 一種是單元測試, 只需要JVM; 另一種是UI或者功能測試, 需要Android.
    emulator會有一些問題: why
    所以你可能想要在更真實的機器上測試: STF提供了服務, 你只需要用這個stf-client.

  4. Deploy:
    部署用一些gradle的task就可以完成.
    fabric
    gradle-play-publisher

後面還提到了一些擴展和問題.

Bottom Sheets in Android

BottomSheet是support library 23.2加入的, 是從底部滑上來的一個塊塊, 用來向用戶展現更多內容.
Support Library提供了:
BottomSheetBehavior: 加在CoordinatorLayout的直接child view上, 然後在java代碼里get出來, 設置state控制其狀態.
有HIDE, COLLAPSED和EXPANDED三種狀態, 分別對應隱藏, 展開到指定高度(peekHeight)和完全展開.
BottomSheetDialog:
BottomSheetDialogFragment.
Behaviour是給View加行為, 後面這兩種是更加模塊化的dialog, 狀態控制都一樣.

這裡推薦一下筆者自己的demo: AndroidDesignWidgetsSample
再推薦一下這篇文章裡面的Bottom Sheets部分: CodePath-Handling-Scrolls-with-CoordinatorLayout

Certificate public key pinning using Retrofit 2

SSL handshake, 交換了證書(Certificate), 這樣客戶端就可以通過證書來驗證伺服器的身份.
什麼是Certificate public key pinning呢? 也叫作SSL pinning.

把host name和public key關聯起來, 這個public key將用來和證書中的public key比較, 如果匹配了, 就證明你正在和正確的server通信.
而直接pinning證書相比pinning public key更容易一些, 但是也有不好的地方, 如果網站(比如Google)經常輪換證書(rotate its certificate), 你的應用就也得經常更新, 而這種情況一般證書裡面的public keys是保持不變的.
如何在Android中用Retrofit實現pinning呢?
首先需要網站的public key的hash, 有很多獲取方法, 參見okhttp3-CertificatePinner.
然後構建CertificatePinner類對象, 加到OkHttpClient上.

 CertificatePinner certificatePinner = new CertificatePinner.Builder()
                    .add("api.github.com", "sha256/6wJsqVDF8K19zxfLxV5DGRneLyzso9adVdUN/exDacw=")
                    .build();
 final OkHttpClient client = httpBuilder.certificatePinner(certificatePinner).build();

  Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl(END_POINT)
                    .addConverterFactory(GsonConverterFactory.create())
                    .client(client)
                    .build();

TLSv1.2從Android16+開始支持, 但是對於20+的設備預設是disabled的, 為了強制獲取支持, 可以繼承SSLSocketFactory, 強制設置為enabled, 代碼見原文吧.
Github上有完整的代碼PublicKeyPinning
作者最後還推薦了一個測試的工具mitmproxy.

Isometric AnimatedVectorDrawable - Part 3

作者繼續講了他如何構建方塊地形圖的動態效果.
一個AnimatedVectorDrawable的xml文件實際上是用來建立一個映射關係, 關聯objectAnimators和VectorDrawable上的獨立元素. 我們可以建立一個objectAnimator, 操縱我們的一塊元素的動畫效果.
文中實現了讓方塊地形動起來的動畫效果.

The many flavors of commit()

FragmentTransaction的提交方法:
support library的FragmentTransaction現在提供了四種不同的方法來commit一個transaction:
commit()
commitAllowingStateLoss()
commitNow()
commitNowAllowingStateLoss()
這篇文章分析了這四個方法的不同.

commit() vs commitAllowingStateLoss():
commit()提交有時候會遇到IllegalStateException, 說你在onSaveInstanceState()之後提交, 這裡有另一個文章很好地分析了這個問題:Fragment Transactions & Activity State Loss
commit()commitAllowingStateLoss()在實現上唯一的不同就是當你調用commit()的時候, FragmentManger會檢查是否已經存儲了它自己的狀態, 如果已經存了, 就拋出IllegalStateException.
那麼如果你調用的是commitAllowingStateLoss(), 並且是在onSaveInstanceState()之後, 你可能會丟失掉什麼狀態呢?
答案是你可能會丟掉FragmentManager的狀態, 即save之後任何被添加或被移除的Fragments.
舉例說明:
1.在Activity里顯示一個FragmentA;
2.然後Activity被後臺, onStop()onSaveInstanceState()被調用;
3.在某個事件觸發下, 你用FragmentB replace FragmentA , 使用的是 commitAllowingStateLoss().
這時候, 用戶再返回應用, 可能會有兩種情況發生:
1.如果系統殺死了你的activity, 你的activity將會重建, 使用了上述步驟2保存的狀態, 所以A會顯示, B不會顯示;
2.如果系統沒有殺死你的activity, 它會被提到前臺, FragmentB就會顯示出來, 到下次Activity stop的時候, 這個包含了B的狀態就會被存下來.
(上述測試可以利用開發者選項中的”Don’t Keep Activities”選項).
那麼你要選擇哪一種呢? 這就取決於你提交的是什麼, 還有你是否能接受丟失.

commit(), commitNow() 和 executePendingTransactions():
使用commit()的時候, 一旦調用, 這個commit並不是立即執行的, 它會被髮送到主線程的任務隊列當中去, 當主線程準備好執行它的時候執行.
popBackStack()的工作也是這樣, 發送到主線程任務隊列中去. 也即說它們都是非同步的.

但是有時候你希望你的操作是立即執行的, 之前的開發者會在commit()調用之後加上 executePendingTransactions()來保證立即執行, 即變非同步為同步.
support library從v24.0.0開始提供了 commitNow()方法, 之前用executePendingTransactions()會將所有pending在隊列中還有你新提交的transactions都執行了, 而commitNow()將只會執行你當前要提交的transaction. 所以commitNow()避免你會不小心執行了那些你可能並不想執行的transactions.

但是你不能對要加在back stack中的transaction使用commitNow(), 即addToBackStack()commitNow()不能同時使用.
為什麼呢?
想想一下, 如果你有一個提交使用了commit(), 緊接著又有另一個提交使用了commitNow(), 兩個都想加入back stack, 那back stack會變成什麼樣呢? 到底是哪個transaction在上, 哪個在下? 答案將是一種不確定的狀態, 因為系統並沒有提供任何保證來確保順序, 所以系統決定乾脆不支持這個操作.

前面提過popBackStack()是非同步的, 所以它同樣也有一個同步的兄弟popBackStackImmediate().

所以實際應用的時候怎麼選擇呢?

  1. 如果你需要同步的操作, 並且你不需要加到back stack里, 使用commitNow().
    support library在FragmentPagerAdapter里就使用了commitNow()來保證在更新結束的時候, 正確的頁面被加上或移除.
  2. 如果你操作很多transactions, 並且不需要同步, 或者你需要把transactions加在back stack里, 那就使用commit().
  3. 如果你希望在某一個指定的點, 確保所有的transactions都被執行, 那麼使用executePendingTransactions().

Break circular dependency with RxJava 用RxJava打破迴圈依賴.

當你把代碼分成各個部分, 比如用MVP, 這些各個部分之間可能會有相互依賴, 比如View需要Presenter, Presenter也需要View.
作者也沒有說雙向關聯有什麼缺點, 但是他說RxJava可以把這種雙向的依賴改成單向的.
作者的辦法是使用RxBinding把button的click事件變成一個Observable, 然後Presenter監聽click這個Observable, 後面接一個flatMap, 裡面髮網絡請求, 得到結果之後再調用view的方法.
這麼一改以後View中就不需要再持有Presenter的引用了.
舉這個例子, 最後是想說, 如果你想從A中調用B的非同步方法, 你不用總是在A中保存一個B的引用, 你可以把A中的事件作為一個Observable. 這樣只需要B保存了A的引用就可以了.

Asynchronous layout inflation 非同步解析layout

最近的support library revision 24中, Google的開發者在v4包中加入了一個新的輔助類AsyncLayoutInflater, 來實現佈局的非同步解析.

我們現在常用的佈局解析inflate方法都是同步的, 那什麼時候需要非同步地做這件事情呢?
比如你想延遲載入佈局中的一塊, 或者你想把佈局解析作為用戶某個交互的一個響應. 這樣就可以用這個非同步佈局解析類, 保證了主線程在inflation進行的時候仍然可響應.
怎麼使用呢?
首先, 在主線程創建對象AsyncLayoutInflater(this),
用它inflate佈局的時候第三個參數是一個OnInflateFinishedListener回調.
以前同步方法的第三個參數是一個boolean, 說佈局是否需要attach到parent上, 現在沒有這個boolean參數了.
當然, 使用非同步解析也有缺點:

  • 父類方法generateLayoutParams()必須是線程安全的.
  • 被創建的所有View不能創建Handler,或者調用Looper.myLooper()方法.
  • 不支持設置LayoutInflater.FactoryLayoutInflater.Factory2
  • 不支持佈局里有Fragment.
    如果我們要非同步inflate的佈局不能支持非同步, inflate的過程將會自動轉化為在UI線程的解析.
    作者文中附有Kotlin的例子.

Introduction to Automated Android Testing - Part 5

系列文章的第五篇, 之前第四篇的時候寫了Presenter, 定義了V和P的介面, 本篇接著寫View介面的實現.

這裡Presenter和View關聯作者寫了兩個attachView()和detachView()方法, 前者在Presenter構造之後調用, 後者在Activity的onDestroy()里調用. 這裡同時會unregister RxJava的subscriptions, 避免了記憶體泄露的發生.

作者在佈局時用了ConstraintLayout, 關於這個layout的使用她有另一個blog
另外作者還加了Toolbar上的SearchView, 到此, 作者的這個app就基本完成了.
作者的代碼里還有一個Injection類, 用來提供retrofit的service, 即代碼中UserRepo的獲取, 在Presenter構造時傳入.

作者的代碼: GithubUsersSearchApp
預告下一篇將會加入UI測試.

DiffUtil is a must!

support library 24.2.0推出了一個新的輔助類DiffUtil, 它是用來解決什麼問題的呢?
如果你的RecyclerView.Adapter第一次接收到了新的數據, 這很簡單, 只需要將它們顯示出來, 但如果已經有了數據, 新的數據又來了, 這時候怎麼做才是最好的呢?
DiffUtil來了, 它就是專門為瞭解決RecyclerView的Adapter更新而設計的, 他可以計算出前後兩個list的不同, 然後返回一組更新操作, 把第一個list變為第二個list.
DiffUtil需要知道你的兩個list的基本信息: 長度, 基本item的比較.
DiffUtil.Callback是用來向DiffUtil提供這些基本信息的, 它是一個抽象類, 你需要繼承它, 然後覆寫裡面的幾個方法. 它的構造傳入了兩個待比較的list, 覆寫的方法主要是get它們的size, 比較它們的內容.
Callback里還有一個getChangePayload()方法, 它不是抽象的, 這個方法在areItemsTheSame() 返回true, 但是areContentsTheSame()返回false的時候被調用.
這意味著我們的item還是之前的那個item,但是可能裡面的欄位變化了.
這個方法的返回值即為兩個對應item的diff, 基本來說, 這個方法返回的是為什麼我們認為list變化了.
文中的代碼例子返回了一個Bundle, 把compare不相等的欄位都放進去了, 用的是new item的值.

一旦我們寫好了這個Callback類, 剩下的事情就很簡單了, 我們只需要在新數據到來的時候計算一下diff, 然後更新.

@ Override
public void onNewProducts(List<Product> newProducts) {
    DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new ProductListDiffCallback(mProducts, newProducts));
    diffResult.dispatchUpdatesTo(mProductAdapter);

}

當然上面getChangePayload()返回的對象還得我們自己利用起來, 它會被DiffResult分發到Adapter.
用的是notifyItemRangeChange(position, count, payload)方法, 傳到了Adapter的onBindViewHolder()方法, 我們判斷payload不為空時, 從裡面拿出diff做更新.

文檔里說DiffUtil對很大的數據集可能比較費時, 所以建議把計算放在後臺線程.

作者還給出了一個RxJava的例子, 各種flatMap.

DESIGN

Diverse Device Hands
Facebook的design資源, 很多拿著手機的手的照片.

LIBRARIES & CODE

unipiazza-android-twostepslogin

一個實現兩步登錄的庫, 比如Google web登錄, Material Design.
要用它的佈局, 然後設置一些屬性, 還有UI交互事件的Listener.

Om Recorder

一個簡單的Pcm / Wav 錄音機, API簡單, 可以錄製Pcm和Wav音頻, 可以配置輸出, 有暫停功能.

tiger

又一個依賴註入庫, 但是README里說這不算一個Google的官方產品, 官方的是DaggerGuice.
這個tiger好像自稱是目前最快的java依賴註入.

NEWS

Taking the final wrapper off of Android 7.0 Nougat
Android 7.0已經問世了, 從Nexus開始, 同時API 24的source code已經push到AOSP了.


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Swift - 實現點擊cell動態修改高度 效果 源碼 https://github.com/YouXianMing/Swift-Animations ...
  • 補充一點遺漏的Xcode配置。 1.偏好設置。Xcode的菜單欄Xcode -> Preference Fonts & Colors可以自定義編碼區和控制台的背景、字體。 Text Editing:Line numbers顯示行數,Code folding ribbon使代碼可以摺疊,page gu ...
  • 1、項目地址 https://github.com/iamMehedi/Secured-Preference-Store 2、使用方法 2.1、存數據 2.2、 取數據 3、xml文件內容 可以看到xml文件裡面的內容都已經變成了混亂的字元,從而實現加密。 4、SecurePreferenceSto ...
  • 一:首先查看一下關於UITableViewCell重用的定義 在tableview新建的時候,會新建一個復用池(reuse pool).這個復用池可能是一個隊列,或者是一個鏈表,保存著當前的Cell.pool中的對象的復用標識符就是reuseIdentifier,標識著不同的種類的cell.所以調用 ...
  • 官方網址:http://snapkit.io/ Github: https://github.com/SnapKit/SnapKit SnapKit is a DSL to make Auto Layout easy on both iOS and OS X. Simple & Expressive ...
  • 一、項目需求 用collectionView展示很多照片,點擊某個照片,用全屏scrollView無限迴圈的方式查看圖片。點擊放大的圖片,圖片縮小到原先的尺寸。 如圖gif1.gif所示,點擊中間的圖片,放大圖片,滑動圖片。再點擊大圖,圖片回到相應的位置。 gif1.gif gif1.gif 如圖g ...
  • Masonry介紹 Masonry是一個輕量級的佈局框架 擁有自己的描述語法 採用更優雅的鏈式語法封裝自動佈局 簡潔明瞭 並具有高可讀性 而且同時支持 iOS 和 Max OS X。可以通過cocoapods將其導入。 Masonry使用 Masonry屬性及其說明 其中leading與left t ...
  • 這篇文章會非常詳細的分析 iOS 界面構建中的各種性能問題以及對應的解決思路,同時給出一個開源的微博列表實現,通過實際的代碼展示如何構建流暢的交互。 Index演示項目屏幕顯示圖像的原理卡頓產生的原因和解決方案CPU 資源消耗原因和解決方案GPU 資源消耗原因和解決方案AsyncDisplayKit ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...