安卓開發常用工具和第三方庫匯總
我的名字叫 Ryan Cooke 我在 Pinterest 的核心體驗團隊工作。今天在這里我會談論各種 Android 庫:它們各自的優點,缺點和其他相關知識。目的是高效地概述盡可能多的庫,這樣,當你遇到一個問題的時候,你知道這是不是個已經解決的問題?什么樣的方案更好?同時也能幫助你避免那些陷阱。
選擇正確的庫意味著你可以擁有一個已經成熟的更好的解決方案,而不是花費三個月來重新構建它。了解這些庫是第一步。
我聽到很多人想要實現第一個庫, 我們難道不能用 Async 任務或原生的東西來做嗎? Google 覺得,如果市面上已經有一個解決方案了,他們就不想建立一個一模一樣的競品。他們在多個地方多次表達過這個想法。但是你應該知道,你還有一些別的選擇。
一般提示
庫最有價值的地方在于 可逆 :你將庫添加到你的應用程序中,之后也可以將其刪除(沒有任何開銷)。隨時都能拿出來。不是所有的東西都可以這樣,但如果它可以的話,請把它做成一個庫,而不是和你的應用終生綁在一起。
一個更好的方法是在把你的庫封裝起來。如果你自己的類調用了庫的方法,那么這樣做就有著許多的好處,可以讓使用者調用你自己的 API。例如,在某些情況下如果庫返回異常,你想在 API 里截獲它。你只用修改一個文件。有一個封裝器讓你的庫更易用些。
如果你正在做一個庫,你的團隊里面的某些人可能已經開始使用它了,他們知道該如何調用你的庫,而不用你的封裝。這個檢查樣式會在編譯的時候拋出異常,或者在應用中當他們為連接類使用 import 語句時,提示他們“不要使用連接類,使用封裝的 API”。你還會指出不要在這個特定文件上這樣做。如果你不這樣做,封裝器用處就不大,因為人們最終會繞過它。
另外, 對第三方庫做單元測試 也是一個好主意。你需要這些測試,如果你正在使用 Joda-Time 這樣的庫,你可以使用單元測試來了解它奇怪的邊界情況。你甚至可以通過單元測試來了解它的工作原理。你可能會發現,如果你不用 add day 方法而是給今天加一的話,你可能會出現二月三十日的情況。
在 Android 的世界中,我們必須考慮 函數數量限制(64,000) 。( 我在說第三方函數庫的函數數量,它們會被精簡掉 )。有一個網站[函數數量](http://methodscount.com),你可以上傳你的庫,Gradle 導入語句,然后它會告訴你這個庫有多少個方法(這是件很棒的事情,特別是當你想使用該庫的時候)。使用 ProGuard,許多庫將會變得很小。這個方法使你只會包含庫中被引用的部分,但是在使用庫之前是很難預測你將要使用的內容的。有些時候你可以這樣做,“我知道我只使用庫的這個方法”,看看它有多小。
Dex函數計數 會在你的 gradle 里,你也可以在你自己的編譯系統上這么做,跟蹤你應用程序中函數的總個數。 Apk-method-count 是一個很棒的工具。你可以拖動你的 APK,看看它有多少個方法(63,905 個方法,我喜歡生活在 64,000 的邊緣)。在 MultiDex 限制出現之前,你添加的每個方法仍將減慢那些舊設備的啟動時間。雖然你的船已經航行,不受 MultiDexing 的限制,十萬種方法和十二萬種方法之間還是有差別的。更少的方法總是有好處的。 Instagram 就是以 從庫 中提取所需的東西而不是使用完整的庫而聞名的。這是一個很好的實踐,如果你有精力這樣做的話。
除此之外,我還建議關注 流行的成熟庫 。每個月(特別是如果你訂閱了 Reddit Android 開發者),你將會聽到最新,最酷的庫。庫越成熟,就會越受歡迎。與現有的項目一起工作,兼容性問題就越少。無論何時遇到問題,stackoverflow 那里都會有答案。
另外,請注意特殊的方法。這是不符合 Java 標準的東西。如果你正在構建完全不同的布局,那么很可能會有兼容性問題。這時采用庫就會變得更加猶豫。
社交登錄
非死book 是社交登錄的黃金標準( 如果你不喜歡 非死book 的實現,情況只會變得更糟 )。他們提供測試用戶,你可以使用這些測試賬戶來測試。不再需要假帳戶了,你應該使用他們的測試帳戶 - 它們工作的更好。我看過有人犯過這樣的錯誤,你不能假設每個 非死book 用戶都有電子郵件。大約 10 到 15% 的 非死book 用戶沒有電子郵件。如果你期待電子郵件,這可能是 10 到 15% 的注冊失敗的神秘原因。他們需要密鑰散列( 這是一個隨機序列,某段代碼打印出的鍵值哈希 ),所以你不必處理它,不用理會它。如果你想申請些其他的瘋狂權限,他們現在已經鎖定了這些權限。他們需要先看看你打算如何使用這些權限,如果你有這個瘋狂的想法而且應用還沒有開發好,請提前告知他們。
登錄和注冊時,請記錄你所得到的錯誤。這是我們如何發現由于沒有電子郵件,10 到 15% 的注冊失敗的方法。有時候記錄錯誤可能是找到你不了解的東西的最有效的方法。
還有很多其他登錄選項:推ter,LinkedIn,Google。我的心態是(特別是 推ter,LinkedIn),雖然他們很受歡迎,但往往不值得的嘗試。你會看到不到 2% 的注冊率,除非是一個非常好的場景。 LinkedIn 提供了非常具有挑戰性的 API( 這不是我原來的單詞,但是 PR 告訴我,我應該改變它 )。 推ter,他們不提供很多信息,但你可以 轉到此鏈接 , 并且說我需要電子郵件和基本信息,他們會給大家授予權限。但總體來說,除非你的架構非常好,這些都會增加你應用的復雜性,。
Google 情況比較復雜。在 Android 上,很多人都會擁有 Google 帳戶。如果他們沒有 Google 帳戶,是非常奇怪的。但是你可以從 Google 登錄中獲得很多功能 - 你可以獲取電子郵件提示和其他東西。此外,登錄 UI 是十分丑陋的。還有點慢,所以你必須考慮加載模式的對話框。
聯網
如果你使用本地庫,那么有兩個大名鼎鼎的庫:Retrofit,Volley。還有 native HTML URL Connect(通常不推薦)。對于 Retrofit 和 Volley 來說,你經常會看到些比較,你會看到 Volley 比 Retrofit 做的更多(例如圖像下載和 neat )。這具有欺騙性。
Retrofit 是由 Square 建造的,他們有一個哲學,他們的庫會盡可能少做事情。他們試圖讓庫嚴格地解決具體的問題,解決這個問題時,強制執行良好的實踐。Retrofit 可能是他們最好的例子。這段代碼( 見幻燈片 )是我在一個應用程序中使用 Retrofit 的示例,我必須為我的 API 調用創建一個非常干凈的接口。
Get more development news like this
Volley 給你足夠的繩子吊死自己。你可以使用 Volley,很容易用錯。Retrofit 更好地強化了最佳實踐,我喜歡這樣的做法。
很多時候你會聽到 OkHttp:這是真正的幕后大舉提升網絡性能的功臣。它已經在 Android 4.4 的 native 里面了。
網絡調試
考慮到網絡調試,你有網絡調用正在進行,你想了解發生了些什么。
Stetho
Stetho 是一個很好的選擇。它是 非死book 開發的。它為你的網絡調用提供了 Chrome 開發者工具視圖。它還提供了許多其他的好東西:可以查看你的數據庫,看看那里發生了什么;可以看到你的布局,如果你不知道屏幕上發生了什么。其中需要注意的是,你必須在每次運行時啟動它,否則它會自動關閉。雖然時間是準確的,但它會使你網絡調用的時間更長。
HttpLoggingInterceptor
我個人傾向于另一個簡單的 HttpLoggingInterceptor。你將攔截器添加到你的網絡請求中,并將其打印在日志文件上。你也可以看到一些 JSON 文件。有一堆類似的東西都命名為 logging 攔截器。使用 Square 的標準 HTTP 日志記錄可以讓你更輕松地瀏覽,非常方便。
圖片
作為在 Pinterest 工作的人,圖片很重要。如果你正在做圖片相關的應用,你可能希望使用第三方庫來處理圖片緩存,圖片下載和圖片大小調整。
Picasso,Glide
圖片處理庫里最有名的兩個庫是 Picasso 和 Glide。他們有著非常相似的接口;對于大多數標準用戶來說接口基本相同。
Picasso 較小。最新版本從 2,879 行縮小到 849 行。但是,Glide 傾向于提供你想要的每個功能:它可以加載 GIF,也可以顯示視頻預覽圖像。
如果你正在加載圖片,Picasso 比較合適。它更受歡迎:它有更多的文檔,更多的支持。兩個庫都很好。如果你一直都有些奇怪的場景,你可以冒險使用 Glide。如果你的使用場景很標準,Picasso 是一個不錯的選擇。
提示
我已經提到我在 Pinterest 工作,而且圖像對我的工作很重要。我必須扔出一堆關于圖像的提示。
人們都沒有做最簡單的事情,因為這些庫沒有這樣做,這件簡單的事情就是在列表中預取。每當你滾動列表時,你都會看到圖像在加載。如果你預取了下一個或兩個圖像,那么當你滾動時,將會減少幀丟失。這會給你帶來更好的體驗,不需要等待加載了。如果你預取的圖像太多,資源就會競爭,也不好,但預取下一個或兩個圖像一定會帶來更好的體驗。
除此之外,這些庫都不能解決你圖像的內存問題。最簡單的做法是禁用圖像,然后計算出應用程序中的圖像消耗了多少內存。不使用圖像,計算出省下的內存消耗。另外,釋放沒有顯示圖像的圖像,并將圖像的大小調整為你顯示的尺寸也可以幫助節省內存。 Cloudinary 是一個很酷的托管服務,你可以以特定的分辨率請求圖像。他們努力做到這點。但是,當你調整請求的圖像大小時,你必須確保你沒有通過請求類似的圖像來破壞緩存(所以這里有個平衡)。
我是 bigHeap 的粉絲。我們的一個的應用程序,使用了 bigHeap 后,內存崩潰降到原來的 1/4。 Google 不鼓勵使用它,因為它關閉了在后臺的其他應用程序,因此應用程序之間的切換并不是那么好。但在某些時候,這不是你的問題。垃圾回收也需要更長時間,你可以使用它來屏蔽內存問題(你不應該這么做)。一般來說,bigHeap 是好的。如果你去 Play Store,并且搜索 largeHeap,你可以下載一個很酷的應用程序,它會顯示你手機上啟用了 bigHeap 的應用程序。你會注意到現在幾乎每個人都陷入了困境,并且正在使用 bigHeap。
當你想到內存和圖像時,這里有一個簡單的公式。有些人會問,“這是個兩千字節的 JPEG,為什么我的實際使用的內存會這么大呢?” 使用的內存是像素寬度乘以像素高度的四倍。這就是你期望的大小。它們的標準格式是 ARGB_8888 - 它用四個字節存儲顏色空間。如果你使用 RGB_565,你可以將其減少到兩倍。但是顏色彼此會非常相似,你會看到更少的色彩空間,它也不能做 alpha,但它會減少一半的內存使用量。你可以考慮在低端設備或低版本 API 上進行此操作。這是節省內存不足問題的好方法。
Fresco
非死book 發布了一個神奇的庫,解決了 API 21 之前的所有版本的內存不足問題。在 API 21 之前,Android 系統中出現了一個錯誤,你可以在應用程序內存之外使用其他的內存。但是會帶來些奇怪的情況:你的程序在舊設備上沒有問題,但在新設備上會表現更糟。因為它加載的方式與其他庫非常不同,所以它可以實現漸進式 JPEG 這樣的圖像,圖像在圖層中逐漸加載。但是,它們會更深入地耦合在你的應用程序中。借助 Glide 和 Picasso,你可以將其與你的應用隔離的很好。而不使用 imageViews,你必須使用它們的類型 Drawees,并且還會產生更多的孤島代碼。
如果你定位較低端的設備,你在舊設備上有更多的內存需求,我建議你使用 Fresco。除此之外,我會堅持 Picasso 和 Glide。
內存 - 泄漏
LeakCanary
LeakCanary 是當今內存泄露的神器,它可以幫助你找到內存泄露的地方。泄漏不是所有的內存問題,但是值得留意。當你將 LeakCanary 添加到應用程序中時,它會自動開始觀察你的 activity 的內存泄漏。有一個我親眼所見的誤用是,他們將 LeakCanary 添加到應用程序中。修復一個或兩個泄漏,然后就認為再沒有更多的內存泄漏了。它只監視了 activity。如果你在這里使用這個代碼( 看幻燈片 ),你可以讓它監視 fragment。這并不意味著你不會在別處泄漏內存。activity 和 fragment 是監測的好地方,但如果你沒有將觀察者設置為對象,你是不知道所有的泄露的。
簡單來說,它的工作原理很酷。作為你引用的任何對象的弱引用:將其附加到你不再被引用的內容中。你把它放在 destroy 代碼段。然后它做垃圾回收。如果對象仍然存在,這就是內存泄漏,所以它知道什么對象依舊存在。它給你那個 home fragment 現場的相關引用。我覺得這很難理解(*有些人認為這很簡單,有人認為這很難。)
這里有個 view 的例子來做點簡單說明( 見幻燈片 )。你從底部開始(這就是泄露的東西)。我有 home fragment。 它被 pin grid fragment 引用 - pin grid fragment 是這個對象的父親。然后我們有這個奇怪的$ 0 - 它解釋說,這是一個可運行的對象。對象內有一個處理程序包含一個 runnable。這段代碼(這不是我的),它是 Android 操作系統的,是處理程序的代碼。處理程序有個 runnalbe 正在運行。我需要確保處理程序不再保留 runnable。在這種情況下,我可以在視圖的 destroy 中清除所有的 runnable 和處理程序,這將修復這個內存泄漏。
WeakHandler
你還可以使用這個隨機工具 WeakHandler,這使得處理程序引用都是弱引用。如果你觸發一個垃圾回收,就可以回收它們。它的缺點是可以被垃圾回收 - 如果你不希望它們被垃圾回收,那可能會出現意想不到的事情。值得注意的是,我遇到的大多數內存泄漏都是無效的,它通常是一個正在運行的 non-missed 的類持有外部類 (這是最常見的地方) 。對于你的內存泄漏,還需要一個 bug 分類的方法。沒有什么比你手機上有 70 個內存泄漏, 而你不知道下一步該做什么更糟糕了。作為一個團隊,弄清楚當我們發現內存泄漏時要做什么,總是一個好主意。
UI
我們都知道我們一直深陷泥潭。Activity 是舊標準。因為你想重用,所以有了 fragment。但是最后我們用 fragment 把 UI 顯示做的異常復雜。試試另一種方法,基于視圖的架構,它更流行。在基于視圖的架構里,你有一個框架布局,而不用處理任何原生的 Android navigation 的東西,你可以用你想要的視圖替換內部的框架布局里的任何東西。希望這能夠解決 fragment 的復雜性。
fragment 已經被簡化了,而且更新了版本,它們現在更加穩定,但是人們依舊爭論著需要有基于視圖的架構。如果我們遵循這個論點,我們應該看看一些庫(圖形的底部, 看幻燈片 )。
基于視圖的架構
這個架構是由 Mortar 和 Flow 引入的。我相信他們是第一批普及基于視圖的架構的庫。 Flow 真正地遵循了基于視圖的架構,但是它們往往是一起的,而 Mortar 主要是 MVP 模式。當你開始實現基于視圖的架構時,請注意這個奇怪的地方。
你還可以找到些更奇怪的地方,那就是如果你的應用是基于 View 的話,你會遇到些隨機的問題,因為這個庫不是基于 View 的。它是基于 activity 的, 如果你的應用是基于 view 的話,你得自己去解決那些問題。比如基于 View 的標準問題,例如 on-activity 的行為,許可等等。即使是后退按鈕和導航,你都不得不自己去解決,只要你是基于 View 的。
Mortar 和 Flow完成基本的導航功能,但它們并不解決所有常見問題(例如屏幕上保存的狀態)。
Conductor正是為這些基于 View 的視圖而生的,它創建了一個解決方案:比如保存狀態,轉換等等。但是你仍然會遇到兼容性問題。總的來說,他們是非常好的,他們是架構不可知的,所以你可以采用你自己的 MV。
Scoop 來自 Lyft。他們在產品中使用它。它是經過產品測試的基于視圖架構的解決方案。它們不保存狀態,所以 Lyft 無法保存狀態。在你將要使用基于視圖的架構的主要常見問題中,這是最大的問題。切換很容易使用,但也很有限,這對于基于視圖的體系結構來說有點令人失望,因為在這種架構下,你往往可以實現很好的切換。
總的來說,如果你不需要保存狀態,Scoop 是可用的,最安全的產品。Conductor 也很好。我會推薦這兩個庫。
模型 視圖 表示(MVP)
有幾個很好的 MVP 的庫。MVP 的基本思想是把邏輯代碼分離出來,這樣視圖部分,Core Android 的東西,會放在一起,然后 presenter 也是分開的,我們可以單元測試這個 presenter。理論上,我們可以改變視圖,而不必完全重寫業務邏輯。
有很多方法來做 MVP。我推薦的第一個庫是 Mosby 。即使你不使用 Mosby,他們也有很棒的教程和 Android 相關的文章( 比如 MVP 應該是什么樣的,它如何工作 )。它主要能提供的功能是給你的 presenter 提供視圖狀態。
Nucleus也很類似。 Mortar ,作為 Mortar 和 Flow 的一部分,是它們早期的版本,它們越升級問題越多。我看到公司常常自己 構建 MVP :在創建時,你將啟動你的 presenter; 銷毀時,你會停止你的 presenter 。每個 activity 或任何你的視圖持有的任何東西都會有一個 presenter。
所有的這些權衡,雖然聽起來很簡單,當你實際操作一個用例時,有很多邊緣案例要考慮。你有你的適配器,你的視圖項目。確保每個人理解的都一樣,并且找到能夠運用 MVP 的地方是最難的部分。但是這樣做的最終結果是你可以獲得更多的可單元測試代碼。你可以獲得更穩定的代碼。
測試 - 性能
NimbleDroid
我有一堆關于測試的內容,但我不想讓你們聽三個小時測試的東西,所以我們跳過使用 JUnit 4 進行單元測試。你有一個 Gradle 構建系統,有 Espresso。這些都是標配。性能測試是個非標的工具。
執行性能測試有兩種主要的方法。 Google 傾向于主張使用 Systrace 類似的方法來查看丟幀率,他們有一個代碼庫,可以為你提供幾乎能直接工作的代碼(但不是很有效)。這允許你進行自動化性能測試,以查看丟幀率是否變化。
NimbleDroid 有一個免費的試用選項,你可以在其中上傳 APK,它將自動測試冷啟動,你也可以增加些應用程序中的關鍵流程。他們提供一個函數發生的時間序列圖和詳細信息。它可以免費進行試用(例如上傳你的 APK 并獲得冷啟動時間,看是否有明顯問題)。如果你想使用它來進行回歸測試,那么它是很貴的,但它會幫助你意識到,有人做了一個改動,我們的啟動時間變慢了,或者我們的關鍵流程慢了。如果性能是一個高優先級的目標,那么使用它是很有效的。
JSON
人們在考慮性能時往往都會想到 JSON。有很多的 JSON 庫。我的第一個警告是:人們喜歡純粹通過性能來看待 JSON 庫。這是一個錯誤。我收到了我最大的請求(150千字節,30,000行,巨大的 JSON 文件)。我分別用 GSON 和 Jackson 解析了它們。它們相差大約 20 毫秒,對于那個巨大的文件來說,這并不瘋狂。
我的第一個建議是:更多地關注易于使用的東西,有很好的文檔的庫。你希望得到支持。你不用花幾個星期讓開發人員嘗試找出原因,就因為 stackoverflow 沒有答案。除非你對性能有超高的要求,GSON 和 Jackson 是使用最多的,最受歡迎的,特別是在 Android 上,GSON 更受歡迎。
Moshi 是 Square 采用的庫。它跟 GSON 非常相似。我試圖就如何使用好 GSON 給出了一些意見。你可以同意或不同意這些觀點,但都不會錯。
如果你關心 JSON 解析性能,并希望它更快,LoganSquare 是一個很好的選擇。它們在編譯的時候完成了其他庫需要在運行時完成的工作。與其他的庫相比,這將使你節約大約 1/4 的時間,或四倍的性能提升。如果你真的關心 JSON 性能,你不應該使用 JSON。
相反,你可以使用 Flatbuffer。 JSON 人類可讀,Flatbuffer 不是,但是因為這樣,它丟掉了其他的不需要的負擔。但是 Flatbuffer 與 JSON 相比,Falbuffer 解析幾乎不花時間。非死book 做了這個轉換。他們發現啟動時間增加了 10% 到 15%,啟動時間有所改善。他們也觀察到內存使用效率更高。但是使用起來比 JSON 更難,所以謹慎使用。
數據庫 - SQL
對于數據庫,我們知道常見的是 SQLite - 標準 Android 庫。
SQLBrite 是 SQLite 上一個常見的簡單庫;它為你提供了數據庫的 reactive 接口。你可以監聽你的用戶。如果你的用戶有任何更改,你會收到通知,你可以隨即更新用戶界面。這是一個非常小的庫。和 SQL 兼容的很干凈。
SQLDelight 也來自 Square。他們寫了很多庫。它試圖避免成為一個完整的 ORM,因為 ORM 會泄漏太多你的代碼,并且往往迫使你做太多的事情,當然它仍然試圖使數據庫的工作更容易些。它使得 API 類型安全,使得 SQL 語句組織的很好(它嘗試使其更容易些,同時不會太重)。
如果你愿意去做一個完整的 ORM,那么有很多很好的庫:GreenDAO,OrmLite,DBFlow 是一些比較受歡迎的( 還有許多其他選擇 )。他們都會說,它們在性能方便表現最好。每個庫都有些圖表,這些圖表顯示它們比其他的方案快 100 倍。我的建議是易用性是第一優先事項,然后再考慮是他們在性能上是不是會更好。
數據庫 - NoSQL
Realm 是 NoSQL 的方法。它超級快。與其他可比較的數據庫不同,Realm 支持的文檔非常多。這可以最終節省你大量的開發時間,而且無所謂數據庫類型。
Google 推薦的另一種 NoSQL 方法是 LevelDB。鍵值對,但是它可以說是 “你能夠弄清楚該怎么做,但你必須自己弄清楚每一步”。 Realm db 可以幫助你避免這種情況。
Realm 數據庫需要特別注意的地方是它的大小( 我認為我們最初添加它時,我們的應用程序大小增加了一倍 )。原因是它是一個本地庫。對于每個芯片架構,它們在你的應用程序中都包含了 Realm 數據庫的完整副本。為了避免這種情況,你可以將此代碼放入 Gradle( 參見幻燈片中的代碼 ),并為每個架構生成一個單獨的 APK。你把它分解成多少個版本,大小就會減少多少。這也會使你的內存節省很多。對于任何本地運行的 C++ 代碼,這是正確的做法,所以在 Crashlytics 和其他一些受歡迎的庫中,你能看到同樣的收益。
還有另外一款很酷的 Google Play 商店的應用程序 Native Lib。 - 它在 Play 商店中,它會顯示些本機庫,以便你可以看到你是否為你的 APK 下載了不適用于你手機的代碼庫。這樣做會減少內存使用。如果你就是在尋找手機上保存數據的方案,你可能希望在手機上存儲數據。如果你正在構建一次性的應用程序,請不要保持數據。如果你正在使用 Realm 在存儲量很小的手機上構建應用(為什么在這種情況下你的應用需要占用大量的存儲)?但總的來說,這是一個非常好的數據庫解決方案。
數據庫 - 移動平臺
另一個方面是移動平臺:移動開發人員的夢想,我們不再需要這些服務器指南。我們也可以自己構建應用程序。以前的 Parse 是最好的例子(可能會安息)。
現在移動平臺中最有名的就是 Firebase 和 Realm。它們都是 NoSQL 模型,它們有一些查詢方面的挑戰,但是構建速度非常非常快。非常適合進行同步更新。聊天是最常見的解決方案,你發送聊天消息,突然所有的手機都能獲取更新。不必構建數據庫,不必擁有服務器,你可以使用其中一個解決方案。它使得構建過程非常迅速,馬上完成應用并推向市場。而且性能也特別好。
Realm 與 Firebase 的區別是它有離線優先的優點。它們都可以脫機,但是 Firebase 是事后補救,而 Realm 是事先就設計好了,Realm 在許多方面都支持離線。許多應用程序幾乎不需要在線行為。如果你正在考慮運行應用跟蹤程序,我們希望同步我們的運行狀態,而且我們希望所有功能都能完全脫機運行,之后在線工作也正常。Realm 就會脫穎而出。
Analytics
我喜歡分析。精益創業的說法是。如果你可以測量它,你就可以優化它。如果你沒有數字的東西,一切都是隨機的,你只能猜想如何使它更好。我喜歡有詳細的分析,來了解這個改變是否使事情變得更好?人們是否使用此功能?如何改善它?
Analytics 是封裝第三方庫的理想選擇。如果你封裝好了 Analytics,那么你應該能夠在不修改任何功能代碼的前提下,完全替代你的分析服務。你應該能夠很容易地添加一個新的 Analytics 服務,以便它們能同時工作。封裝 Analytics 代碼是一個很好的實踐。
如果你正在添加分析數據,最簡單的方法是記錄你的屏幕,記錄人們瀏覽過的屏幕,將其放在抽象的 activity 中。這樣會很快地獲得很多的價值。
我看到人們使用 Analytics 技術的常見錯誤是增加了太多的 Analytics 。他們會在任何地方添加一千個事件,然后沒有人知道這個分析意味著什么。他們沒有進行充分的測試,所以你真實的注冊只有注冊的 2/3。在添加分析時需要非常小心。嘗試使用簡單的命名和標準。不要使用分析來延遲輕松的決定。如果有一個容易的決定,那么請開始。如果你的分析結果告訴你“人們不喜歡釋放內存”,那先假設你的分析是錯誤的。得出一個錯誤的結論是很容易的。如果你有一個很重要的結論,首先要做的是確認你的分析代碼方面沒有什么瘋狂的事情。
Firebase
Firebase 曾經是一個實時數據庫,然后 Google(混淆我們)開始使用一大堆叫做 Firebase 的工具。Firebase Analytics 是所有 Firebase 工具的基礎。Google 意識到 iOS 和 Android 開發人員正在解決同樣的問題。他們正在使用第三方服務并且通過付費來解決所有這些問題。他們認為,我們可以使構建應用程序更加容易,而且構建應用程序更容易,賺的錢就更多。他們做了這些工具的競品。迫使它們更好用,谷歌試圖使分析工具成為所有的工具的基礎。這樣做的愿景是,如果你收到崩潰報告,看到你的分析數據,你可以按照崩潰的投資回報率給它們排序。你的通知系統也參與其中,你可以發送通知給那些碰到最昂貴的崩潰的客戶,并告訴他們一些免費的折扣。我們知道你即將購買,因為你是一個高價值的崩潰。
這是個很酷的愿景。還沒有實現,實話實說。有些工作正常,有些還在開發中,這不是谷歌最高的優先級的任務。但是很多工具還是很好的(不如競爭對手的工具)。 Analytics 雖然是免費的。但是事件不受限制。沒有太多的理由不使用它。
另一個流行的是 Google Analytics(分析)。它很容易地獲得許多關于用戶的基本信息。這是我看到的唯一一個提供很酷的行為流程圖的工具,在那里你可以看到人們在你的事件之間切換。它還是有點過時了,其記錄事件的風格比所有其他分析工具更舊。它也是免費的,Firebase 意在替換它。
A / B 測試
我個人認為 A / B 測試被過度宣傳。通常它被用于慢速學習,以便你了解的更清楚,如果是簡單的命名規則就不適用了,當然你可以將其投放到用戶手里,你會發現,100 個用戶的樣本中,55% 偏好了這一選擇。這就是你通常看到的 A / B 測試。
它很容易產生 Bug。基本上,A / B 測試中應用程序版本數是你應用程序中的 A / B 測試數加 2。如果你的應用程序中有 3 個 A / B 測試,那么就有 8 個不同版本應用程序一起工作。你可能沒有測試各種不同版本的應用程序。有時候你可能會發現因為這些問題,往往會導致重要的決定不太容易做了。
我的解決方案是用戶分析服務。 Mixpanel 具有非常好的 A / B 測試工具,而且和你的分析工具兼容。有許多工具用于 A / B 測試。我想說最有名的是 Optimizely 和 Apptomize。Optimizely 更適合網頁( 他們的價格 都有點神秘)。他們幫助你提供不同的版本,告訴你這是一個比另一個有顯著的更好的統計學差異的版本。
Firebase Remote Config 在技術上可以用來進行 A / B 測試。它不是用于 A / B 測試的。它是用來在不需要開發人員的更新的情況下,從服務器發送鍵值對的,但是這能讓我們做 A / B 測試。你可以發送兩個不同版本的鍵值對,然后你可以使用代碼來決定要做什么。之后,你可以將其傳遞到你自己的分析界面,并找出解析它的方法。從某個角度說,如果你使用 Firebase 遠程配置,你是在創造輪子。
你也可以使用 A / B 測試商店列表。這是值得嘗試的,特別是你在不同的國家里測試。這是比較容易的,你可以在那里獲得一些收獲。
崩潰報告
像分析一樣,有一千個解決方案。 我只打算介紹少數幾個
人們首先看到,特別是 Android 新手,那就是 Play 商店。每當你遇到崩潰時,你可以選擇發送報告。大家都會直接忽略,大約 1% 的崩潰出現在 Play 商店中。有時候,如果你的用戶數非常大,而且有些非常神秘的崩潰,那可能值得去看看,因為人們會對發生的事情發表評論。也就是說,你有 1% 的崩潰; “99% 的人說應用很爛,崩潰”。但是每隔一段時間,就會有這樣的評論 “我在手機上旋轉了屏幕,它崩潰了”( 你好像是,啊,一個開發者,我很感激 )
Crashlytics 趨勢是最受歡迎的。這是 推ter 的 Fabric Suite 或者說是現在的 Google Fabric Suite 的一部分。它是免費的,并為你提供一個非常好的,高級的,有組織的崩潰視圖。你仍然需要自行排序和確定優先級。它有一些問題,很難搜索和查詢。我看到人們聯合使用 Bugsnag,這樣查詢和搜索會更好一點。 Bugsnag 是相當不錯的,但它不是免費的。
Instabug 和 Telescope。Telescope 是個庫。你把它放到 bug 里,作為第三方服務。這些庫的優點不是監控 crash,而是讓你在問題出現時,搖晃手機來報告問題。這樣,當你的團隊中的設計師看到錯誤時,他們不用在 JIRA 里提交 Bug,或者和別人說明所有的步驟然后讓別人來報 bug,但是你仍然希望這些不是 crash 的 bug 也能被修復。有這么一個工具,所有的測試用戶,alpha 用戶,你公司的人,看到錯誤都能告訴你,這些問題需要修復。
推送通知
作為開發人員,第一反應是使用 GCM 或現在的 Firebase Cloud Messaging,這些庫正在重組。但是這些工具對營銷人員不友好。最簡單的情況是,如果你已經有了很好的分析服務,Firebase 和 Mixpanel(以及其他許多庫)都可以用來發送通知。你可以根據你的 activity 發送消息。可以這樣設計,一個從來沒有發生過購買的人,做了三次搜索,這時你可以給他們發送一個通知,建議他們買些東西。這是最簡單的情況。
有時你會想要一些更深入的東西。Urban Airship 的推送通知特別專業,這是他們的主要方向。他們發現,“人們只會看到通知的前 60 個字符”,我們都會收到這樣的通知,你只能看到前面幾個字。就像,“你不會相信這個…”,它被截斷了。然后你點擊它,你被帶到一個隨機的屏幕里,你甚至不知道推送通知的內容是什么。Urban Airship 很好,他們幫助你思考這樣的事情,給你更多的細微差別提示,思考如何能更好地推出通知服務。
Kahuna 很受歡迎,有很多人都在使用它,但我會強烈反對。他們的想法很棒。通過借助 AI 來幫你確定哪種推送方式更合適,是發送電子郵件,還是發送短信或者是推送通知。AI 計算出最好的推送時間,并建議通知上需不需要添加花朵。這部分他們還沒有實現。但他們現在會做些文字上的變化。他們試圖讓通知受人喜愛,盡可能地推送最合適的通知,想法很酷,希望它能很快實現。但是現在,現實實現中,他們遇到了很多問題,用戶的通知被發送給錯誤的用戶。用戶被合并在一起,視為一組。所以使用時請小心。有些人用的很好。但我被坑了。
更輕松
有很多偉大的工具能使你的開發更容易些。
一個工具是 Butter Knife(@indVView)。它使你的代碼更漂亮。你可以使用 @BindView 通過 ID 查找視圖,而不必遍歷所有的視圖。Zelezny,是一個Android Studio 插件。把它放進 Layout 中,它會自動生成 BindViews 和 OnClicks。如果你以前一直是手敲代碼,它會節省點時間。最大的限制是 annotation 的處理會破壞增量編譯。如果你有 Butter Knife,那么你可能會比沒有 Butter Knife 時的增量編譯慢些。對我個人而言,我喜歡所有的 annotation 處理工具,船已航行。我已經接受了 annotation 處理器打破我的增量編譯的現實。我聽說有人建議將它們全部放在同一個模塊中可以解決這個問題。這是唯一的缺點,許多 annotation 處理都會有這個問題。也許有一天這個問題會被修復。 JRebel 聲稱一些特定版本的增量編譯已經修復了。除此之外,Butter Knife 是最好的選擇。
Hugo 是個 Jake Wharton 的庫(* 當我說 Jake Wharton,一半的時候是指 Square,它們是同一個意思*)。它是一個輕量級的庫,你可以在方法之上執行 @Debug.Log,然后打印出該方法花費的時間,以及參數。它特別適用于現場性能記錄。 “我需要緩存這個變量嗎?它被調用太多了以至于變慢了嗎?”你可以看到,“不,這只花了 10 毫秒,我應該把它放在一個后臺線程上,或者花了不到一毫秒,我們不用擔心這個”。它很容易納入你的代碼,并迅速獲得相關數字。
Dart & Henson,你有 intents ;不需要使用鍵值映射,它給你應該有的值。它做了點 annotation 的映射來展示 intents 的值是什么。我更喜歡的另外一種理解方法是你正在調用的 activity 的靜態 intents 。這樣,你可以傳入你想要的參數,這樣就解決了神秘的鍵值對的問題。它使得代碼更加緊密,這樣可以防止錯誤。
如果你喜歡 lambdas,你應該使用 Retrolambda。需要注意是它產生四種方法,而不是正常的匿名類。我認為使用 Retrolambda 會使得代碼不易讀,這是你必須做出明智決定的地方。
更困難(初期)
我們來談一談哪些庫會讓開發變得更加困難,或者說開始的時候更困難。但總的來說,這些都是好工具。
RxJava
RxJava,對于那些沒有聽說過的人來說,這個庫的想法是,過去的代碼從 A 點開始,到 B 點結束。但在 Android 世界中,移動開發世界中,這一切就都不一樣了。 *你從 A 點開始。然后人們點擊某些東西,所以你必須做些別的事情來響應。然后一個通知進來,你必須又做些事情。然后數據庫請求出現了。Reactive 努力使你的代碼能夠對你的應用程序中的發生的事情做出反應,幫助你更好的組織它們,而且方便移動。
起初很難,因為它有一個學習曲線。如果你正在看代碼,特別是對于沒有接觸過 RxJava 的人來說,會有許多不清楚的地方。最簡單的就是網絡。但是,如果你有幾個標準的例子,你使用這些案例,并確保是最佳的做法,情況就會不一樣了。當你開始擁有這些功能時,它們非常強大,你可以將其運用于應用程序中的任何地方,但是當你這樣做的時候,每當雇用新的開發人員,你將不得不教會他們每個 activity 是怎么工作的,這需要很小心。
此外,它很容易用錯。即使是關于 RxJava 的許多會議都會漏掉一些最佳做法。例如,如果你不取消訂閱網絡呼叫,那么你會被回調,這時可能會發生崩潰,因為屏幕已經不存在了。謹慎地使用它,總體上來說它還是很好的。
Kotlin
當我說小心使用非內建語言或者說新語言不尋常的地方時,我想說的就是那些你能看到的不尋常的地方。 Kotlin 生成了更整潔的代碼。這有好處。使你的代碼更容易閱讀,也會使沒有意義的東西少一些,這是你需要的核心東西。它也隱藏了指針的概念。
最大的缺點是它會隨機地破壞事情,如果有什么事情發生,你都會懷疑 Kotlin。這可能是 Kotlin 的錯,可能不是,但是都會花掉開發人員的許多時間,來弄清楚到底是不是 Kotlin 的錯。你需要更新 Gradle 的構建,然而這依舊不奏效。這可能是 Kotlin 的錯,也可能不是 Kotlin 的錯,但是你都不得不重新檢查 Kotlin。
同樣的情況是,你的 Android Studio 也會隨機崩潰,或者 ProGuard 不工作了,因為它去掉了一些 Kotlin 的類。這些事情經常發生,很難扭轉。Kotlin 有很多權衡點。我們在代碼中使用它。確實有一些問題,與此同時,了解 Kotlin 的人們的代碼審查更快。對于不知道 Kotlin 的人來說,有一個學習的曲線。這是一個權衡。你必須自己決定。
相機
如果你曾經在 Android 中使用過 Camera,而且你采用的是原生的方案,這并不瘋狂,你會發現有攝像頭 one API 和攝像頭 two API,而且攝像頭 two API 沒有比攝像頭 one API 更好,如果你同時支持新舊設備,你必須使用攝像頭 one API,除非你只打算在非常新的設備上正常運行。我的第一個建議是,如果你有使用相機的場景,構建一個 intent。讓其他人的相機應用來解決你的問題,如果這不是你的核心場景的話。
如果不是這種情況,有一個名為 Material Camera 的庫,我以前 fork 過。你可以添加自己的外觀。它幫助你創建相機。解決問題。但是當你按照本教程進行首次設置后,橫向顯示時,圖片會顛倒,你不得不在每個手機上都進行測試,因為他們會以不同的方式安裝相機。還有很多邊界案例要考慮。Material Camera 是偉大的,它已經把這些情況都解決了。它也支持視頻。這是視頻模式。你可以改變它上面的 UI,效果很好。再說一次,如果 Camera 是你非常核心的用例,那么你應該重新構建它,這只是個折衷的方案。
我使用的每個相機應用都有裁剪功能,這個功能很可怕。我不知道是什么原因。你試圖剪裁,突然間你的視頻被剪掉了中間部分。有一個很好的庫叫做 “Android Crop”。它提供了一個非常簡單的新的 activity 來完成剪裁。
全球思考
作為 Android 的開發人員,我們需要考慮到世界各地的所有開發者。如果你正在為世界各地的開發人員做些開發工作,有些事情你必須考慮,比如網絡仿真:你希望能夠在低質量網絡上進行測試。Android 上做到這點比 iOS 難。仿真器技術可以提供本地仿真器 AVD,但通常情況下,我的經驗是,如果你在模擬器上進行任何 3G 操作,沒有應用工作正常。我的一些應用程序有時候能在 3G 上正常工作。
我知道的最成功的工具是 Charles 代理。你可以配置經過某個代理。這很容易設置。你可以告訴代理,下載速度應該是多快。但仍然有一個挑戰,你需要知道網絡可能有多快。比如說像巴西的 3G 網絡,幾乎是一個無意義的聲明 - 3G 在巴西各處都不一樣,在各地都是非常不同的。某些時候,你必須嘗試找一些數字,選擇一些數字。
外面有些資源,但是選擇參數是挑選網絡仿真最困難的部分之一。有一個名為 Augmented Traffic Control 工具,它來自 非死book。它允許你連接到服務器或設置路由器,你可以設置配置文件 - 當你連接到路由器時,你的互聯網應該有多快。如果你有非開發人員為你測試,他們仍然可以連接到這個 WiFi 網絡并設置他們擁有的連接級別。產品經理和測試人員一般也應該考慮質量較差的網絡。 ATC 服務器很好用。
我相信新的 Android O 暗示他們會有類似于 AutoFitTextView 的東西,但現在這只是一個庫,只要文本對于文本框來說太大,文本就會縮小。如果你正在翻譯德語,它的很多字母比英文還是要大一些,那么它會把它縮小到框中。這不是你的第一個翻譯解決方案,但最好讓它們縮小到文本框的大小,而不是填滿整個屏幕并覆蓋所有內容。它將調整你的文本大小(更改你的文本大小來適應),這是一個很好的安全的翻譯。
YearClass 是 非死book 的另一個庫。它會告訴你,運行你產品的最新的手機生產年份是多少。如果我們說 2015 年是最高的年份,那你就不用關心 2016 年制作的手機上的一些特別的事情。從分析角度來說,這是最好的 - 比如這個崩潰是,發生在 Android OS Marshmallow 上,所有的手機都是低功耗的手機,有時候會發生這種情況。知道一下 crash 在不同年份的手機上的發生概率可以幫你對這個 crash 有更深的了解。
Connection 類是理解用戶連接質量的一個非常好的工具(* 這是我在開始時推薦的封裝樣本類)。它對網絡進行分類。不是分成 4G 3G,因為它們變化很大,它依據的是帶寬,分為優秀,好,中度或差,或未知。它通過采樣下載速度來分類。然后它會移動平均值。這樣做的價值是,例如,你是一個顯示許多圖像的圖像網站,你可能希望在較差的網絡上降低圖像質量,或著執行其他操作。預先知道帶寬可以做許多事情。
最大的警告是它的抽樣可能是不合時宜的。你能做的事情是讓它們開始采樣和停止采樣。比如,當我打開應用程序時,開始采樣,當我關閉應用程序時停止。它們做的事情是查看你下載的數據量,每秒刷新一次。如果用戶將你的應用程序打開,并且沒有進行任何操作,他們會認為你的網絡慢的可怕。我們所做的是,你可以在網絡調用或者圖像調用的中間啟動它,這樣做的效果很好。除此之外,這個庫對你的網絡帶寬了解的很準確。
About the content
This content has been published here with the express permission of the author.
來自:https://academy.realm.io/cn/posts/tools-and-libraries-for-common-android-problems/