記一次View.getContext()遇到的大坑

lqlwoaini 7年前發布 | 20K 次閱讀 安卓開發 Android開發 移動開發

有的時候不能盲目自信,不然會踩到大坑啊,哎。。還是因為太菜了。

事情的經過是這樣子滴: 有一個特殊條件,需要把View的context強轉為Activity。

大概是這樣子的:

imageView.context as Activity
 

這個時候我是比較確信這個view的context一定是Activity的,所以沒有加以下判斷。

if (imageView.context is Activity)
 
 

然后坑就來了。。 4.x該蹦的全崩了。。當時我的心情猶如股市大跌,想要去跳樓。

確信的理由

為什么我當時認為這個context一定是Activity呢,其實不是沒有理由的。因為我的imageView是寫在xml里的,大家都知道,setContextView(),其實就是PhoneWindow的setContentView():

發現這個view是LayoutInflater解析xml反射出來的。view的context就是LayoutInflater的mContext:

這個LayoutInflater的context是PhoneWindow傳進去的:

PhoneWindow的context就是Activity的this:

所以,也就是說,一個寫在xml里的View,他的context就是Activity。 源碼是這樣告訴我的。可是為什么4.x都崩了呢,4.x的view的context到底是什么呢?

刨根問底

如果你聽過LayoutInflaterFactory,那么大概就能想出是什么原因了,代碼是不會騙人的,可是為什么View的context變了呢,那只能是有其他代碼在搞鬼。所有Appcompat的Activity,創建View的時候,都會對基本View做一個風格的包裝,也就是說ImageView會變成AppcompatImageView。 那么實際上,imageView.context 是AppcompatImageView的getContext().

研究發現,AppcompatImageView并沒有重寫getContext()方法,那么到底怎么回事呢,直接看他的構造器:

臥槽,坑爹呢這是! 發現即使context傳進來是個activity,也回被包裝成TintContextWrapper。

那么為什么5.0以上系統,獲得的還是一個Activity呢?

繼續看:

nnd,原來如此,看樣子是v7包為了能加載到一些特殊資源,給包裹成了TintContextWrapper。 所以強轉出錯!!!

這個故事告訴我們,就算你有絕對的自信,你也不能保證你百分百正確,該遵守的一些優良習慣,還是要養成的。。

 

來自:http://androidwing.net/index.php/225

 

 本文由用戶 lqlwoaini 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!