Android Weekly Notes Issue #223

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

Android Weekly Issue #223 中文筆記, 本期內容包括: Offline時間戳處理; Accessibility的安全問題可能並不是個問題; 如何在單元測試和UI測試之間共用代碼; Android中的指紋認證; 編譯時間Kotlin vs Java; MVP結合RxJava,... ...


Android Weekly Issue #223

September 18th, 2016
Android Weekly Issue #223

本期內容包括:
Offline時間戳處理; Accessibility的安全問題可能並不是個問題; 如何在單元測試和UI測試之間共用代碼; Android中的指紋認證; 編譯時間Kotlin vs Java; MVP結合RxJava, 讓View來處理生命周期; RxJava2預覽; 記憶體泄露處理; Gradle相關等等.

ARTICLES & TUTORIALS

Offline First: Introducing TrueTime for Android

TrueTime是一個NTP library for Swift and Android.

其中NTP是Network Time Protocol.

作者他們有一個購物app, 但是時斷時續的網路降低了用戶體驗, 所以他們進行了離線遷移, 準備出一系列文章分享相關的想法和在此過程中學到的東西.

本文是第一篇, 關於時間.

由於在設置里可以設置設備的日期和時間, 所以設備的時間並不一定是真實的時間, 我們在程式里new Date()得到的其實是設備時間.

關於真實時間的計算, 他們開源了TrueTime庫, Android和iOS都能用.

TrueTime如何計算真實時間的呢? 它其實是向NTP的server發了請求, 然後計算出的.

文中和庫都說明瞭用法.

Android Security and Accessibility

之前有一個文章說Accessiblity存在安全隱患, 這個服務可能可以訪問到一些隱私信息, 比如密碼.

但是這篇文章的作者覺得前一篇文章作者的解決方案不是很好.

因為當用戶開啟Accessibility許可權的時候, Android就已經給出了警告, 說明敏感信息可能會被觀察到. 第三方的keyboard也可以訪問這些信息, Android也是在開啟的時候給出了警告.

另外對於前一篇文章作者提出的解決方案: View.IMPORTANT_FOR_ACCESSIBILITY_NO
這樣真正有視覺障礙的那部分用戶也無法看到密碼, 可能就無法登陸了.

所以本文作者建議的解決方案是, 可以彈一個對話框來提醒用戶, 如果用戶允許了, 再繼續輸入.

Sharing code between UI & unit tests

Android的測試分兩種:

一種是Unit tests. 單元測試, 在JVM上跑.

另一種是UI測試, 需要Android設備.

在Android Studio中對應testandroidTest文件夾.

這兩個測試文件夾之間是不共用代碼的, 即一個文件夾里不能訪問另一個裡面的代碼.

但是如果我們想要共用一些代碼, 是有辦法解決的.

首先在app/src下新建一個文件夾, 比如叫testShared. 裡面添加要共用的代碼.

然後在app/build.gradle裡面添加這個:

android.sourceSets {
    test {
        java.srcDirs += "$projectDir/src/testShared"
    }

    androidTest {
        java.srcDirs += "$projectDir/src/testShared"
    }
}

就可以在UI測試和單元測試中共用同一份代碼了.

Synchronously Animating Colors on Android

作者想做的一個效果是, 在切換tab的時候, 把Toolbar, TabLayout, FloatingActionButton還有StatusBar的顏色都動畫地改變到另一個顏色.

實現很簡單, 首先用當前顏色和目標顏色建立一個ValueAnimator, 然後addUpdateListener()在更新的過程中把值set給相應的控制項:

colorAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animator) {
        int color = (int) animator.getAnimatedValue();

        toolbar.setBackgroundColor(color);
        tabLayout.setBackgroundColor(color);
        floatingActionButton.setBackgroundTintList(ColorStateList.valueOf(color));

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            getWindow().setStatusBarColor(color);
        }
    }

});
colorAnimation.start();

其中FloatingActionButton要用setBackgroundTintList().

StatusBar在21及以上才支持getWindow().setStatusBarColor(color);

Android Fingerprint Authentication

其實用戶都不喜歡驗證, 因為用戶都比較懶, 不喜歡一次又一次地輸入密碼或者手勢pattern, 但是不鎖屏又不安全.

指紋驗證Fingerprint Authentication是Android M (Android 6.0, API 23)引入的. 它就是為瞭解決這個問題, 提升用戶體驗. 這種non-disturbing和easy的方式, 讓我們不用在安全和用戶體驗之間做出妥協.

如果你的應用需要做一些關鍵操作, 比如支付, 你需要用戶在操作前授權, 那麼指紋驗證會很有幫助.

然後作者介紹了實現的細節.

最後作者附上了自己的相關庫: fingerlock.

Kotlin vs Java: Compilation Speed

這是作者關於Kotlin的第三篇文章, 作者在這篇文章里測試了Kotlin和Java的編譯時間.

Clean build with No Gradle daemon
Java編譯比Kotlin快17%.

Clean build + Gradle daemon
org.gradle.daemon=true

Java編譯比Kotlin快13%.

Incremental builds
kotlin.incremental=true

在clean build的時候, Java可能快10-15%, 但是在增量build + gradle daemon時, kotlin和Java一樣快, 甚至可能比Java更快一些.

Let the view handle the lifecycle in MVP by using RxJava

問題:
作者舉了一個例子, 在Fragment作為View的MVP中, 如果P從service取一些數據, 然後調用View的顯示方法, 則還需要知道onViewCreated()是不是已經調用過了.

解決方案:

首先創建一個Lifecycle的BehaviorSubject, 在onViewCreated()的時候調用onNext(null).

把View的方法改成返回一個Observable, presenter的方法調用View的方法時實際上是subscribe了一下:

class ProductsFragment implements ProductsView {
  private ProductsPresenter presenter;
  //Lifecycle subject. It is BehaviourSubject because it can be subscribed after onViewCreated call.
  private final BehaviorSubject<Void> onViewCreatedSubject = BehaviorSubject.create();

  @Override
  public Observable<Void> showProducts(List<Product> productList) {
    return onViewCreatedSubject. // Wait for onViewCreated
        doOnNext(new Action1<Object>() {
          @Override
          public void call(Object o) {
            //Updates recyclerview adapter items
          }
        });
  }

  @Override
  public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    onViewCreatedSubject.onNext(null);
  }
}

Presenter:

class ProductsFragmentPresenter implements ProductsPresenter {
  private ProductsView view;

  public void loadProducts(){
    productsService.getProducts()
      .flatMap(new Func1<Object, Observable<Void>>() {
          @Override
          public Observable<Void> call(List<Product> productList) {
            //Return the view's observable to show products.
            //No need to check if the view is created!
            return view.showProducts(productList);
          }
        })
      .subscribe();
  }
}

當然這並不是一個完整的例子, 完整的例子還需要考慮onDestroyView()還有註銷等情況的處理.

Nougat - GCM Network Manager

作者搞了一個message app來研究Android 7的新特性.

他用到了AutoValue.

關於Android 7的另一篇文章: Random Musings on the N Developer Preview

他們的應用首先需要周期性地生產一些消息, 關於生產消息的實現, 作者沒有用AlarmManager, 也沒有用JobScheduler(因為只支持API 21及以上), 而是選用了GCMNetworkManager.

具體實現見原文, 有詳細說明.
另: 代碼

這隻是系列文章的第一篇, 後續應該會寫更多.

TransactionTooLargeException crashes on Nougat

作者自己的應用在Activity轉換的時候遇到了一個crash: java.lang.RuntimeException: android.os.TransactionTooLargeException: data parcel size 700848 bytes.

之前應用里有相關的Warning log, 但是
Android 7 Nougat (API 24)把它作為異常拋出來了.

產生這個問題的原因是在onSaveInstanceState()裡面存了太多數據. 作者做了一個測試, 想看看這個限制大概是多少, 大概是500K左右.

所以這裡是不應該用來存儲太多數據的, 應該只存狀態.

底下回覆說每個進程都有1M的buffer來接收transactions, 但是是在沒有任何其他IPC的情況下. 所以建議存儲的狀態數據少於100K或者50K, 當然越少越好.

Building a blazing fast ETC2 compressor

作者是Google的, 以前做游戲的, 所以致力於Performances, GPU, 數據壓縮等內容.

作者關註VR, 但是VR中要提升體驗, 必定會增加圖像的大小和質量.

ETC textures 是OpenGLES 3.0的一種標準格式.

編碼一個高質量的ETC2 texture會花費很多時間.
以在游戲界最流行的壓縮工具Mali GPU Texture Compression tool為例, 作者做了實驗, 證明確實要花費很多時間(平均10分鐘)來encode一個圖.

所以作者他們開發了一個新的庫: etc2comp, 一個很快的texture encoder.

然後和之前的工具做了比較, 平均時間提高到了10秒.

後來他說的技術細節我就看不懂了. 文後還有其他圖像格式(JPG, PNG, WebP)相關的文章鏈接.

Low Coupling With Rx and Dagger2 in Android

作者舉例展示Android程式的解耦.

首先, 他展示一個高度耦合的Android程式, 然後加入Rx, 最後加入Dagger2, 從而一步一步地解耦這個項目.

項目的內容是發現Network中的Services. 這裡有官方的Training: Network Service Discovery.

RxJava2: An Early Preview

最近RxJava2有了第一個Release Candidate. 所以作者在這裡先預覽一下有哪些有趣的更新和新加的功能:

New Dependency:
添加了依賴: ReactiveStreams.

Imports:
RxJava2放在了一個不同的package下:

RxJava:

compile ‘io.reactivex:rxjava:1.0.y-SNAPSHOT’

RxJava2:

compile ‘io.reactivex.rxjava2:rxjava:x.y.z’

這意味著, 你可以同時用兩個版本的庫. 如果你要完全遷移的話, 你需要把所有的import都改到新包.

Null Emissions No Longer Permitted:
不允許再發送null值了, 會直接拋出空指針異常.

Observable.just(null); //don’t do this
subject.onNext(null); //don’t do this either

Under(Back)Pressure:

Backpressure是當Observable發射值的速度比Observer能處理的速度快時發生的.

RxJava2引入了一個新的Observable類Flowable, with backpressure support.

Single Old and New:
訂閱一個Single現在可以用這個:
SingleObserver<T>.

Hit Me Maybe One More Type:
一個新的類型叫Maybe, 它是SingleCompletable的混合體. 用來發射0或1個值.

New BackPressured Subject: Processor:
引入了一個新類型, Processor, 它是一個有backpressure support的Subject.

New Names for Function and Action:

  • Func1 -> Function
  • Func2 -> BiFunction
  • FuncN -> Function<Object[], R>
  • Func1<T, Boolean> -> Predicate<T>
  • Action0 -> Consumer
  • Action1 -> BiConsumer
  • ActionN -> Consumer<Object[]>

Subscriber is Now Disposable:

因為和Reactive-Streams的命名衝突, 所以Subscriber改名為Disposable. 它有一個.dispose()方法, 類似於Subscription.unsubscribe()方法.

onCompleted()也將變為onComplete().

Composite Subscriptions Changes:

CompositeSubscription + subscribe()-> CompositeDisposable + subscribeWith()

Blocking Calls:
RxJava2加了一些新的操作符來變非同步為同步.
.toBlocking.first() -> .blockingFirst()

Better Hooks for Plugins:
plugin系統被重寫了. 現在你可以覆寫內置schedulers返回的值了. 這樣你就可以在做單元測試的時候覆寫Schedulers.io()來返回同步的值, 甚至debug Schedulers.

Summary

目標Release日期: October 29.

Retrofit已經支持RxJava2了:
retrofit-rxjava2-adapter

這裡還有一個Library用來把RxJava1轉換到RxJava2: RxJava2Interop

Sources:
RxJava 2.x javadoc,
Github Wiki: What's different in 2.0,
Stackoverflow

Eight Ways Your Android App Can STOP Leaking Memory

之前作者有個文章叫Eight Ways Your Android App Can Leak Memory, 講的是Android應用中8種記憶體泄露的原因, 主要是泄露了Activity.

這篇文章主要講解決方法:

Static Activities

錯誤原因: 把Activity存在一個靜態引用里, Activity生命周期結束後仍然持有.

解決方法:
使用WeakReference.

Static Views

錯誤原因: 靜態引用了View, 因為attached View引用了Activity, 所以等於間接引用了Activity.

解決方法:

  1. 使用WeakReference;
  2. 在onDestroy()裡面把引用置為null.

Inner Classes

內部類分兩種, 靜態內部類和非靜態內部類: Nested Class

錯誤原因: 在Activity里有一個內部類(非靜態), 創建內部類的對象, 然後靜態引用之. 因為內部類持有外部類的應用, 所以會造成記憶體泄露.

解決方法:
儘量不要存static引用.

匿名內部類 AsyncTask, Handler, Thread, TimerTask

錯誤原因:

如果你不在超出生命周期的地方引用它, 匿名內部類的對象是無害的.

但是上面的這些內部類對象全都是用來產生一些線程的, 這些線程是app全局的, 而且會引用創建它們的對象.

解決方法:

  1. 把上面的這些類改成靜態內部類, 靜態的內部類對象不會引用外部類的對象.
  2. 如果你堅持使用匿名內部類, 可以在Activity的onDestroy()裡面終止線程.

Sensor Manager

錯誤原因:

把Activity作為listener註冊給了系統服務, 但是在Activity生命周期結束之前沒有註銷listener.

解決方法: 在生命周期結束前註銷listener.

Auto rename Android versionName in Gradle

在應用release的時候, 版本號是確定的, 這沒問題. 在應用開發的時候, 如果每一個apk也有一個特定的版本號, 將會非常有幫助.

自定義Gradle Plugin:
com.android.application就是一個gradle plugin.

有三種方式可以創建gradle plugin: doc.

本文作者選擇了buildSrc的方式, 因為這很容易, 而且可以被加到repo里, 但是這樣將依附於你的project, 不能復用.

具體代碼見原文.

這麼做了之後, 每一次build的apk都自帶了分支信息, Jira卡號, 或者任何你想帶的信息.

Is your custom view interactive aware?

什麼是Interactive View?
當View是可見的, 即可以和用戶交互, 即為interactive.

當你的自定義View做一些很重的工作, 比如迴圈的動畫或者loading, 或者依賴於感測器, 當這種View變為不可見時,你需要做一些工作來節約電量.

作者寫了一個輔助類: InteractiveViewHelper 來做這個.

具體利用了View的這幾個回調:

void View::onVisibilityChanged(View, int)
void View::onWindowVisibilityChanged()
void View::onAttachedToWindow()
void View::onDetachedFromWindow()

還有兩個ACTION:

Intent.ACTION_SCREEN_ON
Intent.ACTION_SCREEN_OFF

Beta Testing Your Android App With Build Variants

講瞭如何用Build Variants, 添加不同的Flavors.

Make your build.gradle great again

1. 把你的build.gradle分成小份, 更加模塊化, 用apply應用.

2. 在build file里指明application id.

applicationId是apk最終會用的包名.
packageName是用來找代碼中的R, 和activity/service組件的相對路徑.
如果不在build文件里指明applicationId可能會有一些問題.

3. 給debug版使用一個不同的applicationId.

buildTypes {
    debug {
        applicationIdSuffix ".debug"
    }
    // ...
}

好處是同一個機器上可以同時安裝debug和release版.

4. 統計build時間.

用--profile命令. 或Build Scans

還可以用build-time-tracker-plugin

5. 配置release.

Proguard在Java層面工作, 對於資源是不管的, 只把R中的id刪了.
如果想進一步處理不用的資源, 需要加:
shrinkResources true.

更深一步的居然還可以拆分apk: config-apk-splits

6. 發現一些有用的tasks, 或者自己開發. Reddit page.

7. 把依賴的版本號抽出來.

8. 使用jcenter, 響應更快.

9. 在開發時把最小sdk設為21或以上, 會build得更快.

LIBRARIES & CODE

Android Amazing Open Source Apps

這篇文章列舉了一些好的開源app.
包括google/iosched, android-architecture, Telegram, Plaid, wire-android, ribot/ribot-app-android, PocketHub.

DoorSignView

一個自定義View, 顯示門牌. AnimatedDoorSignView可以根據感測器進行動畫.

Java Error Handler

一個統一的錯誤處理器. 為每一種錯誤建立全局預設的處理方式.


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

-Advertisement-
Play Games
更多相關文章
  • 開本系列,討論一些有趣的 CSS 題目,拋開實用性而言,一些題目為了拓寬一下解決問題的思路,此外,涉及一些容易忽視的 CSS 細節。 解題不考慮相容性,題目天馬行空,想到什麼說什麼,如果解題中有你感覺到生僻的 CSS 屬性,趕緊去補習一下吧。 不斷更新,不斷更新,不斷更新,重要的事情說三遍。 所有題 ...
  • 摘要: 版權聲明:本文為博主原創文章,未經博主允許不得轉載。 大概花了4,5天時間,做了一個對資料庫幾張表的維護的系統,採用的是MVC4+easyui構建,先附上幾張截圖讓大家瞭解下: 功能無非就是,增,刪,改,查,分頁顯示,功能很簡單,但是,主要是講下碰到的幾個問題: 一,大家都知道,通過點擊左邊 ...
  • IE7 下,不能夠自定義<select>/<option>的樣式,所以為了方便起見,用div可以進行模擬 註意事項:1、如果有多個併列,互相之間會相互影響,IE7下,會被遮擋,為避免此問題,所有 設置層級為:1,選中時,層級改為22、<a>標簽,缺少herf屬性的話,IE7下將無hover效果3、使 ...
  • 使用volley進行網路請求:需先將volley包導入androidstudio中 File下的Project Structrue,點加號導包 volley網路請求步驟: 1. 創建請求隊列 RequestQueue queue = Volley.newRequestQueue(this); 2.創 ...
  • 本文結合之前的動態創建fragment來進行一個實踐,來實現用Fragment創建一個選項卡 本文地址:http://www.cnblogs.com/wuyudong/p/5898075.html ,轉載請註明源地址。 項目佈局 新建Fragment1.java~Fragment4.java,其中F ...
  • 大家好,好久沒有跟新了。其實也就昨天到今天的時間。 前言:實際上,GIF動圖文件中包含了一組圖片及其信息數組,這些信息數據記錄著這一組圖片中各張圖片的播放時長等信息,我們可以將圖片和這些信息或取出來,使用UIImageView的幀動畫技術進行動畫播放。 好了不多說了 開始上代碼吧: 首先自己找一個G ...
  • 隨著Android應用開發規模的擴大,客戶端業務邏輯也越來越複雜,已然不是簡單的數據展示了。如同後端開發遇到瓶頸時採用的組件拆分思想,客戶端也需要進行架構設計,拆分視圖和數據,解除模塊之間的耦合,提高模塊內部的聚合度。 開始之前先上一張內部分享時用的PPT圖: 以上是筆者在客戶端開發過程中面臨的問題 ...
  • 1、SpannableString、SpannableStringBuilder與String的關係 首先SpannableString、SpannableStringBuilder基本上與String差不多,也是用來存儲字元串,但它們倆的特殊就在於有一個SetSpan()函數,能給這些存儲的Str... ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...