每日一問:淺談 onAttachedToWindow 和 onDetachedFromWindow

基本上全部 Android 開發都會接觸到 onCreate()onDestory()onStart()onStop() 等這些生命週期方法,但卻不是全部人都會去關注到 onAttachXXX() 這樣的方法羣體,今天,筆者就但願用簡短的文章對此進行必定講解。佈局

Activity 中的 onAttachedToWindow

首先在 Activity 中咱們能夠重寫 onAttachedToWindow()onDetachedFromWindow() 這一對方法。顧名思義,"Attached" 就是附加的意思,因此咱們能夠肯定 onAttachedToWindow() 就是在 View 附加到 window 上的時候進行回調,而 onDetachedFromWindow() 就恰好相反。post

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

這裏天然咱們容易產生一個問題,在 onAttachedToWindow() 回調的時候,咱們能拿到 View 的寬高麼?換句話說就是這時候 View 是否已經通過了測量和繪製呢?日誌

咱們編寫一個 Demo 進行日誌打印看看。
code

能夠看到,並無。咱們只有在 onWindowFocusChanged 回調的時候才能真正的拿到 View 的寬高值。blog

因此,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 吧。

相關文章
相關標籤/搜索