天天看點

你真的了解 Android 中的 Context 麼?

概述

在使用getContext方法的時候有沒有想過,在不同的場景下,取到的Context到底有什麼不同,View,Fragment,Activity和Application的getContext又究竟是怎麼樣?

下面來分析一下。

擷取Context DecorView

DecorView的Context是Application Context。

ActivityThread.addView -> PhoneWindow.generateDecor

你真的了解 Android 中的 Context 麼?
View

一般View是從LayoutInflater類中inflate生成的,檢視inflate方法,會調用rinflate

你真的了解 Android 中的 Context 麼?

發現是入參Context,在inflate方法内指派,其實最後就是LayoutInflater.from的參數Context。

是以結論是普通View是LayoutInflater.from的參數Context。

但是對于xml這樣的布局檔案裡面的View又是怎麼樣的呢?

看一下Activity.setContentView方法的調用過程是:

Activity.setContentView -> PhoneWindow.setContentView -> LayoutInflater.inflate方法,而這個LayoutInflater是在PhoneWindow的構造方法内建立的,回到Activity.attach方法,看到構造方法的參數是Activity的Context。

你真的了解 Android 中的 Context 麼?

于是增加一個結論,在xml中解析的View的Context屬于Activity。

可能有人問,那Fragment也是嗎?看一下Fragment.onCreateView中參數有LayoutInflater,跟蹤一下

Fragment.onCreateView <- Fragment.performCreateView -> FragmentManagerImpl.moveToState <- Fragment.performGetLayoutInflater <- Fragment.getLayoutInflater <- FragmentHostCallback.onGetLayoutInflater

結果是用了FramgentHostCallback構造方法的參數Context

你真的了解 Android 中的 Context 麼?

結論也是Activity的Context。

FragmentActivity

一般使用FragmentActivity.this和FragmentActivity.getContext方法取到Context,最終取到的都是Activity的Context,不再贅述。

Fragment

通過Fragment.getContext取到Context,結果是取到FragmentHostCallback.getContext也是Activity的Context。

Application

取到的是Application Context。

Applicaiton與Activity的差別

是以最終的目的是區分Application與Activity的Context有什麼不同。是以看它們各自的實作,Application與Activity都繼承于ContextWrapper,ContextWrapper就是包裝了一下抽象類Context,在構造方法裡傳入Context對象,根本在于建構Application和Activity的地方。

追蹤一下發現Context建構都在ContextImpl類内,Application對應createAppContext,而Activity則對應createActivityContext,都在ActivityThread中調用各自建立Context方法進行初始化。

你真的了解 Android 中的 Context 麼?

對比ContextImpl的建構,前三個參數都一緻,Activity的Context多了activityToken和classLoder,其中activityToken對應ActivityRecord類,接着調用Context.setResource方法設定Activity的配置和邏輯顯示相關的資訊Display。

你真的了解 Android 中的 Context 麼?

看一下這個熟悉的錯誤,這個是使用Application的Context啟動Activity時報的錯誤,這個mSourceRecord就是AcitivityRecord對象,對于Application而言為null,是以需要指定New_Task這個标志。

兩者之間更重要的一個差別是:生命周期。

對于Application的Context而言,在整個應用的生命周期内都不會改變;而對于不同的Activity,其Context有可能不同,例如添加一個Dialog必須附着在Activity上,是以使用Application就會報錯。

你真的了解 Android 中的 Context 麼?
總結

除了Application,DecorView和getApplicationContext方法會取到Application Context外,其他方法getContext都會取到Activity Context或者傳入的Context。

一般來說,Application Context存在于整個應用的生命周期中,不會随場景變化而改變,是以對于打開不同的Activity,Activity Context可能存在不同,而且生命周期跟Activity的生命周期一緻。

原文釋出時間為:2018-11-22

本文作者:豆沙包67

本文來自雲栖社群合作夥伴“

安卓巴士Android開發者門戶

”,了解相關資訊可以關注“

”。

繼續閱讀