InputMethodManager內(nèi)存泄漏引發(fā)對View加載的探究

? ? ? ? ?本文主要以InputMethodManager內(nèi)存泄漏為引,來探究在不同系統(tǒng)版本中View是如何被加載的谭网,涉及以下幾個方面 :

(1)如何解決InputMethodManager內(nèi)存泄漏教藻;

(2)為何View.getContext() 是TintContextWrapper冠骄;

(3)不同系統(tǒng)版本中View是如何被加載的锁摔。

一损离、如何解決InputMethodManager內(nèi)存泄漏

? ? ? ? 在企鵝FM最新版本開發(fā)中,正好負責項目性能監(jiān)控(主要是ANR禁谦、內(nèi)存泄漏等等)這一塊胁黑,在內(nèi)存泄漏這塊發(fā)現(xiàn)有很多InputMethodManager泄漏的上報,引用鏈如下:

圖1 inputMethodManager內(nèi)存泄漏引用鏈

? ? ? ? 在很早之前就聽說過InputMethodManager存在泄漏問題州泊,查閱了一下相關資料丧蘸,大多數(shù)是InputMethodManger中mServedView存在泄漏,而非圖1中的mLastSrvView 遥皂,不太應該啊 ?力喷,難道是某個版本rom的特殊機型刽漂,對照相關郵件發(fā)現(xiàn)全部都是華為機型。

? ? ? ? ?項目中內(nèi)存泄漏這塊弟孟,使用的是MagnifierSDK(【SNGAPM】Magnifier SDK介紹)贝咙,其中ActivityLeakSolution中有專門解決InputMethodManager泄漏的解決方法,如下圖2所示:

ActivityLeakSolution::fixInputMethodManager

從上述解決方法中可以看出拂募,主要針對的是mCurRootView庭猩、mServedView、mNextServedView陈症,為什么添加這些蔼水,本文在這里就不展開講解了。

? ? ? ? 后面在同事的提醒下發(fā)現(xiàn)項目中有專門針對華為機型進行處理的方法录肯,方法原理簡單粗暴徙缴,直接置空,破壞掉path to gc節(jié)點(同MagnifierSDK中ActivityLeakSolution::fixInputMethodManager處理方式一樣)嘁信。

圖3 針對華為mLastSrvView進行處理

? ? ? ? 既然同MagnifierSDK中ActivityLeakSolution::fixInputMethodManager處理方式一樣于样,為何沒生效了,回頭再去圖1中的引用鏈潘靖,從中發(fā)現(xiàn)了蛛絲馬跡穿剖,RadioSearchActivity 是TintContextWrapper 中的mBase 引用,而TintContextWrapper::mContext 又是被SearchView$SearchAutoComplete引用卦溢,由此猜想圖3中的view.getContext()==destContext條件可能失效糊余。后續(xù)驗證發(fā)現(xiàn)上圖中View.getContenxt ?確實是 TintContextWrapper 而非引用鏈中的RadioSearchActivity ,如下圖4所示:

圖4 查看 view.getContext()

二单寂、為何View.getContext()是TintContextWrapper

? ? ? ? 為何View.getContext()是TintContextWrapper贬芥,而不是RadioSearchActivity。帶著疑問去查看SearchView$SearchAutoComplete(這里的SearchView是使用support v7庫)為何物宣决,發(fā)現(xiàn)SearchAutoComplete直接繼承AppCompatAutoCompleteTextView蘸劈。

圖5 SearchAutoComplete

? ? ? 在AppCompatAutoCompleteTextView 的構造函數(shù)中,會將傳入的context(這里指的是RadioSearchActivity)wrap成TintContextWrapper尊沸,可以方便的實現(xiàn)Android Material Design 中的Tint威沫。

圖6 AppCompatAutoCompleteTextView

? ? ? ?現(xiàn)在雖然弄懂了這個案例中View.getContext()是TintContextWrapper的原因,那是不是所有的View都存在這樣的情況了洼专,在什么時候會轉化了棒掠,帶著這些疑問去探究一下View是如何加載的。

三屁商、不同系統(tǒng)版本中View是如何被加載的

? ? ? 總所周知烟很,Activity 加載布局時,調(diào)用的是activity的setContentView()方法來加載布局;而在Fragment中雾袱,是直接通過LayoutInflater來加載布局的恤筛。如果大家對setContentView()內(nèi)部實現(xiàn)機制比較清楚的話(如果不清楚,可參看 從源碼角度剖析 setContentView() 背后的機制)谜酒,一定知道Activity加載布局也是使用LayoutInflater,因此可以認為Activity和Fragment加載布局方式一致妻枕。

? ? ? ? 由于目前官方推薦使用AppCompatActivity代替Activity僻族,當前企鵝FM項目已全部替換成了AppCompatActivity,因此在這里的探究是基于AppCompatActivity來講解的屡谐。

圖7 AppCompatActivity

從圖7可知述么,在AppCompatActivity::onCreate()中有一個AppCompat的代理類AppCompatDelegate(一個抽象類),其具體實現(xiàn)如下愕掏,對應著不同版本的具體實現(xiàn)類度秘。

圖8 AppCompatDelegate實現(xiàn)類

接著看一下delegate.installViewFactory 內(nèi)部實現(xiàn)(項目中存在support v22 和 v23,兩者存在差異)饵撑,

圖9 support v22
圖10 support v23

從上可以看出v22 和v23 installViewFactory 實現(xiàn)存在微小差別剑梳,在使用Factory的時候要特別注意,這里不展開滑潘,具體可參見 從源碼角度深入理解LayoutInflater.Factory 垢乙。installViewFactory中主要進行的是setFactory操作,其中上面的this 指的就是 LayoutInflaterFactory 语卤,那LayoutInflaterFactory 又是什么了 追逮?

LayoutInflaterFactory 是一個接口 ,提供了一個耳熟能詳?shù)姆椒╫nCreateView 如下:

圖11 LayoutInflaterFactory

onCreateView 這個回調(diào)是在createViewFormTag進行的粹舵,熟悉setContentView的同學一定清楚钮孵,在 public View inflate(XmlPullParser parser,@Nullable ViewGroup root, booleanattachToRoot)中會通過createViewFromTag()方法來創(chuàng)建View。

圖12 ?createViewFromTag()

? ? ? ?到此大家應該明白了吧 眼滤,View 替換是在inflate 的createViewFromTag() 進行的巴席,不同版本的實現(xiàn)又是通過setFactory 來實現(xiàn)的。

由上文知在installViewFactory 中 使用的是AppCompatDelegateImplV7诅需,那AppCompatDelegateImplV7::onCreateView() 實現(xiàn)又是怎樣的情妖,如下圖所示:

圖13 AppCompatDelegateImplV7::onCreateView()

在createView 里面創(chuàng)建了AppCompatViewInflater

AppCompatViewInflater::createView?

? ? ? ? 沒錯系統(tǒng)就是在AppCompatViewInflater中將部分系統(tǒng)View 全部替換成了 AppCompatView ,而在AppCompatxxx中會將普通的Context wrap 成TintContextWrapper ,到此整個View的加載過程講完诱担。

另外毡证,這里補充一下 LayoutInflaterFactory 接口用途(實際開發(fā)中很少會使用):

1)自定義的View,而不是讓系統(tǒng)去創(chuàng)建蔫仙,避免反射過程料睛,提高性能;

2)在xml使用自定義的View時,可以不聲明全限定名稱恤煞;

3)更換系統(tǒng)View為自己定義的View(Appcompat庫替換默認的系統(tǒng)View的方式)

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末屎勘,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子居扒,更是在濱河造成了極大的恐慌概漱,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件喜喂,死亡現(xiàn)場離奇詭異瓤摧,居然都是意外死亡,警方通過查閱死者的電腦和手機玉吁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門照弥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人进副,你說我怎么就攤上這事这揣。” “怎么了影斑?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵给赞,是天一觀的道長。 經(jīng)常有香客問我矫户,道長塞俱,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任吏垮,我火速辦了婚禮障涯,結果婚禮上,老公的妹妹穿的比我還像新娘膳汪。我一直安慰自己唯蝶,他們只是感情好,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布遗嗽。 她就那樣靜靜地躺著粘我,像睡著了一般。 火紅的嫁衣襯著肌膚如雪痹换。 梳的紋絲不亂的頭發(fā)上征字,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天,我揣著相機與錄音娇豫,去河邊找鬼匙姜。 笑死,一個胖子當著我的面吹牛冯痢,可吹牛的內(nèi)容都是我干的氮昧。 我是一名探鬼主播框杜,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼袖肥!你這毒婦竟也來了咪辱?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤椎组,失蹤者是張志新(化名)和其女友劉穎油狂,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體寸癌,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡专筷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了灵份。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片仁堪。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡哮洽,死狀恐怖填渠,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情鸟辅,我是刑警寧澤氛什,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站匪凉,受9級特大地震影響枪眉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜再层,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一贸铜、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧聂受,春花似錦蒿秦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至碗旅,卻和暖如春渡处,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背祟辟。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工医瘫, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人旧困。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓登下,卻偏偏與公主長得像茫孔,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子被芳,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容