每日一問:淺談 onAttachedToWindow 和 onDetachedFromWindow


基本上所有 Android 開發都會接觸到 onCreate()onDestory()onStart()onStop() 等這些生命周期方法,但卻不是所有人都會去關注到 onAttachXXX() 這樣的方法群體,今天,筆者就希望用簡短的文章對此進行一定講解。

Activity 中的 onAttachedToWindow

首先在 Activity 中我們可以重寫 onAttachedToWindow()onDetachedFromWindow() 這一對方法。顧名思義,"Attached" 就是附加的意思,所以我們可以確定 onAttachedToWindow() 就是在 View 附加到 window 上的時候進行回調,而 onDetachedFromWindow() 就剛好相反。

這一對方法會在我們熟悉的 Activity 生命周期的 onResume()onPause() 中間,但並不是每一次 onResume()onPause() 回調的時候都會在接下來回調它們。應該比較好理解,我們當然不需要頻繁往 window 中附加和分離 View 嘛。

這里自然我們容易產生一個問題,在 onAttachedToWindow() 回調的時候,我們能拿到 View 的寬高么?換句話說就是這時候 View 是否已經經過了測量和繪制呢?

我們編寫一個 Demo 進行日志打印看看。

可以看到,並沒有。我們只有在 onWindowFocusChanged 回調的時候才能真正的拿到 View 的寬高值。

所以,ActivityonAttachedToWindow() 回調之后,布局中的 View 會回調 onAttachedToWindow() ,然后才會去進行測量和繪制等。那么我們要獲取一個 View 的寬高就最好是 View.post() 了。

View 的 onAttachedToWindow 使用場景

ViewonAttachedToWindow() 的調用時機會發生在 onMeasure() 之前,那么它們到底有什么使用場景呢?

我們在自定義 View 的時候,某些比較重量級的資源,而且不能與其他 View 通用的時候,就可以重寫這兩個方法,並在 onAttachedToWindow() 中進行初始化,onDetachedFromWindow() 方法里釋放掉。

比如 Bitmap,雖說現在不用主動調用 recycle() 方法來回收,但在 8.0 及以上系統,手動調用是會立即釋放所占用的內存的,所以個人認為還是有必要手動回收的,當然了,如果圖片比較小,對內存沒什么影響的就不用了。

再比如一些用作計算的子線程,或其他跟 View 顯示有關的任務,在 onDetachedFromWindow() 中也可以停掉了,因為大多數情況下,這些實時數據對於被分離后 View 已經沒有意義了。

RecyclerView.Adapter 的 onViewAttachedToWindow

細心的小伙伴會發現,在 RecyclerView.Adapter 中也會有這么一個 onViewAttachedToWindow()onViewAttachedToWindow()

這兩個方法在列表布局的時候,用作曝光埋點非常好用,當 Adapter 創建的 View 被窗口分離(即滑動離開了當前窗口界面的)的時候,onViewAttachedToWindow() 會被直接回調,反之,在列表項 View 在被滑動進屏幕的時候,onViewAttachedToWindow() 會立馬被調用。

有了這樣的屬性,對於我們的曝光埋點,就手到擒來了,直接在里面做就完事兒了。

RecyclerView.Adapter 咋還有一個 onAttachedToRecyclerView

說到 AdapteronViewAttachedToWindow,咋發現這里面竟然還有一個 onAttachedToRecyclerView 方法,根據源碼我們可以發現,onAttachedToRecyclerView() 是在 setAdapter() 的時候觸發。

對比一下,我們便能得出以下它們的使用場景:

  1. RecyclerView 本質上也是一個 ViewGroup,那么它的 Item 要顯示出來,自然需要 addView() 進來,移出的時候,當然也要 removeView() 出去,所以對應的自然是 onViewAttachedToWindow()onViewAttachedToWindow() 了。所以在一定場景下,可以通過這兩個回調來處理一些 Item 移出屏幕,移進屏幕鎖需要的工作。為什么說一定場景下呢,因為如果調用了 notifyDataSetChanged() 方法的話,會觸發當前在屏幕中的所有 Item 的 onViewAttachedToWindow()
  2. onAttachedToRecyclerViewonAttachedToRecyclerView() 的話,就更加適合做一些資源回收的工作啦。

我的 RecyclerView.Adapter 的 onViewAttachedToWindow 為啥沒起作用?

可能會有小伙伴會遇到這個問題,在遇到這個問題前,先檢查一下你這個 RecyclerView 是否是一個正常滾動的 View,你如果是被別人嵌套滾動,把自己設置了 isNestedScrollingEnabled 為 false 的話,那你都失去了 Recyclerview 的功用了,那自然是不行的。

可能又有小伙伴說了,由於需求歷史原因,我就是用了 NestedScrollView 嵌套了 Recyclerview,並禁掉了 Recyclerview 的滑動功能,但又想做上面的曝光埋點功能,那如何是好?

如果是這樣的話,大概你就只能通過類似 ViewgetGlobalVisibleRect() 這樣的方法來判斷 View 的可見性來處理了。關於 View 的可見性分析,這里就點到為止,大家就自行 Google 吧。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM