天天看點

Android項目中多次操作SharedPreferences導緻ANR場景的解決系列文章目錄項目背景:以定位來擷取廣告的方式為例:所遇到的挑戰:解決問題的步驟:問題的解決最近朋友推了一篇位元組的部落格(以下文字以及圖檔來源于位元組今日頭條團隊)。友盟平台相關SDK初體驗:總結

系列文章目錄

Android項目中多次操作SharedPreferences導緻ANR場景的解決

文章目錄

  • 系列文章目錄
  • 項目背景:
  • 以定位來擷取廣告的方式為例:
  • 所遇到的挑戰:
  • 解決問題的步驟:
  • 問題的解決
  • 最近朋友推了一篇位元組的部落格(以下文字以及圖檔來源于位元組今日頭條團隊)。
  • 友盟平台相關SDK初體驗:
  • 總結

項目背景:

随着時代的進步,移動端廣告的投放變得越來越多樣化,為了接近市場,不少公司自己研發了SDK去收集使用者的一些資訊以及行為用于分析,根據分析結果使用自定義廣告(自定義View)的方式繼續向使用者進行展示,以提高展示率和點選率。

目前關于廣告商方面的選擇,國内的廣告變現普遍較低,首選應該是接入谷歌廣告。随着業務的發展,在一段時間後,公司開始轉變成廣告接收方,并靠自己的SDK來進行廣告的投放,以及優化。

以定位來擷取廣告的方式為例:

  • 首先利用使用者的定位等權限來擷取經緯度
Android項目中多次操作SharedPreferences導緻ANR場景的解決系列文章目錄項目背景:以定位來擷取廣告的方式為例:所遇到的挑戰:解決問題的步驟:問題的解決最近朋友推了一篇位元組的部落格(以下文字以及圖檔來源于位元組今日頭條團隊)。友盟平台相關SDK初體驗:總結
  • 将經緯度上傳至國内某定位SDK,擷取具體資訊。
    Android項目中多次操作SharedPreferences導緻ANR場景的解決系列文章目錄項目背景:以定位來擷取廣告的方式為例:所遇到的挑戰:解決問題的步驟:問題的解決最近朋友推了一篇位元組的部落格(以下文字以及圖檔來源于位元組今日頭條團隊)。友盟平台相關SDK初體驗:總結
  • 最後根據定位資訊來擷取廣告并預加載為廣告展示做準備。
    Android項目中多次操作SharedPreferences導緻ANR場景的解決系列文章目錄項目背景:以定位來擷取廣告的方式為例:所遇到的挑戰:解決問題的步驟:問題的解決最近朋友推了一篇位元組的部落格(以下文字以及圖檔來源于位元組今日頭條團隊)。友盟平台相關SDK初體驗:總結

所遇到的挑戰:

在項目功能完成後準備上架前,會對項目進行一系列的測試,但是ANR問題在測試過程中很難完成複現,在使用多個機型測試的過程中幾乎沒有ANR問題的記錄。但是在使用者的實際使用過程中,由于Android碎片化的嚴重,加上使用者的一些操作的習慣等,會導緻出現ANR的問題。面對一些大型的廠家,ANR出現時會彈窗引導使用者關閉軟體,會導緻使用體驗不好,造成使用者的流失。

解決問題的步驟:

在項目一個多月的異常收集中,出現過幾次ANR的問題。

  • 分析異常收集中ANR日志将問題鎖定在SharedPreferences 上,排查過程比較麻煩,在鎖定了問題後,開始對問題進行分析。
  • 檢視Android文檔:在項目中,團隊使用SharedPreferences讀寫配置檔案,均采用了官方的推薦做法,調用apply來送出,調用這個方法時,先寫入記憶體中,再将任務加入隊列中,會在異步線程中做落盤的操作,這個操作理論上來說是沒有問題的,也是google官方推薦的做法。
  • 閱讀源碼:
    Android項目中多次操作SharedPreferences導緻ANR場景的解決系列文章目錄項目背景:以定位來擷取廣告的方式為例:所遇到的挑戰:解決問題的步驟:問題的解決最近朋友推了一篇位元組的部落格(以下文字以及圖檔來源于位元組今日頭條團隊)。友盟平台相關SDK初體驗:總結

    在此過程中發現谷歌官方注釋:

    If another editor on this SharedPreferences does a regular commit() while a apply() is still outstanding, the commit() will block until all async commits are completed as well as the commit itself.

    翻譯:如果SharedPreferences上的另一個編輯器執行正常的commit(),而apply()仍然未完成,則commit()将阻塞,直到所有異步送出以及送出本身都完成。

  • 鎖定問題:主線程調用了

    QueuedWork.waitToFinish()

    ,沒有待執行的任務,直接執行 finisher,進行阻塞等待, 直到寫入檔案成功後恢複執行, 這時候如果等待時間過長, 在一些市面上性能差的中低端機型上就會很容易出現ANR。 (8.0以下)

問題的解決

當時的優化:

1.減小sp對應的檔案的大小,按照分類去讀寫對應的sp檔案。

2.sp的讀寫輕量的、小的配置資訊,将類似JSON的資料交給其他方式儲存。

3.當需要多次調用Put系列方法,當邏輯确認不需要立即讀取時,在最後一次調用commit或apply即可。

最近朋友推了一篇位元組的部落格(以下文字以及圖檔來源于位元組今日頭條團隊)。

  • 思路:如果能讓sPendingWorkFinishers.poll()傳回為null,則這裡的等待行為直接就跳過去了,sPendingWorkFinishers是個ConcurrentLinkedQueue集合,可以直接動态代理這個集合,覆寫poll方法,讓其永遠傳回null,這個時候UI永遠不會等待子線程寫入檔案完畢,事實證明這種方式簡單有效。
    Android項目中多次操作SharedPreferences導緻ANR場景的解決系列文章目錄項目背景:以定位來擷取廣告的方式為例:所遇到的挑戰:解決問題的步驟:問題的解決最近朋友推了一篇位元組的部落格(以下文字以及圖檔來源于位元組今日頭條團隊)。友盟平台相關SDK初體驗:總結
  • 針對這種寫入等待的ANR問題,還有一種就是全局替換寫入方式,通過插樁的方式,替換所有的API實作,采用其他的存儲方式,這種方式修複成本和風險較大,但是後期可以随機的替換存儲方式,使用比較靈活。

友盟平台相關SDK初體驗:

由于ANR的比較難複現,于是寫一個方法,反複對SharedPreferences進行操作,以達到類似情況的複現。

Android項目中多次操作SharedPreferences導緻ANR場景的解決系列文章目錄項目背景:以定位來擷取廣告的方式為例:所遇到的挑戰:解決問題的步驟:問題的解決最近朋友推了一篇位元組的部落格(以下文字以及圖檔來源于位元組今日頭條團隊)。友盟平台相關SDK初體驗:總結

出現問題,通過友盟U-APM平台定位:

Android項目中多次操作SharedPreferences導緻ANR場景的解決系列文章目錄項目背景:以定位來擷取廣告的方式為例:所遇到的挑戰:解決問題的步驟:問題的解決最近朋友推了一篇位元組的部落格(以下文字以及圖檔來源于位元組今日頭條團隊)。友盟平台相關SDK初體驗:總結

找到問題後,進行文中思路的操作即可。

總結

在情景中,由于Android太過碎片化,又不得直接舍棄低版本使用者,采用接入類似友盟U-APM平台的方式去更快的解決問題是必不可少的。但對于一些小型手機的低版本可能還是會出現ANR的問題,針對類似收集使用者行為的情景,可采取進行多種方式去進行收集,例如對于低版本的系統,降低對收集資料的完整性等。