編輯:關於Android編程
Context在android中的作用不言而喻,當我們訪問當前應用的資源,啟動一個新的activity的時候都需要提供Context,而這個Context到底是什麼呢,這個問題好像很好回答又好像難以說清楚。從字面意思,Context的意思是“上下文”,或者也可以叫做環境、場景等,盡管如此,還是有點抽象。從類的繼承來說,Context作為一個抽象的基類,它的實現子類有三種:Application、Activity和Service(估計這麼說,暫時不管ContextWrapper等類),那麼這三種有沒有區別呢?為什麼通過任意的Context訪問資源都得到的是同一套資源呢?getApplication和getApplicationContext有什麼區別呢?應用中到底有多少個Context呢?本文將圍繞這些問題一一展開,所用源碼版本為Android4.4。
Context是一個抽象基類,我們通過它訪問當前包的資源(getResources、getAssets)和啟動其他組件(Activity、Service、Broadcast)以及得到各種服務(getSystemService),當然,通過Context能得到的不僅僅只有上述這些內容。對Context的理解可以來說:Context提供了一個應用的運行環境,在Context的大環境裡,應用才可以訪問資源,才能完成和其他組件、服務的交互,Context定義了一套基本的功能接口,我們可以理解為一套規范,而Activity和Service是實現這套規范的子類,這麼說也許並不准確,因為這套規范實際是被ContextImpl類統一實現的,Activity和Service只是繼承並有選擇性地重寫了某些規范的實現。
首先,它們都間接繼承了Context,這是它們的相同點。
不同點,可以從幾個方面來說:首先看它們的繼承關系
Activity的繼承關系
Service和Application的繼承關系<喎?/kf/ware/vc/" target="_blank" class="keylink">vc3Ryb25nPjwvcD4KPHA+PGltZyBzcmM9"/uploadfile/Collfiles/20140520/2014052008424051.jpg" alt="\">
通過對比可以清晰地發現,Service和Application的類繼承關系比較像,而Activity還多了一層繼承ContextThemeWrapper,這是因為Activity有主題的概念,而Service是沒有界面的服務,Application更是一個抽象的東西,它也是通過Activity類呈現的。
下面來看一下三者在Context方面的區別
上文已經指出,Context的真正實現都在ContextImpl中,也就是說Context的大部分方法調用都會轉到ContextImpl中,而三者的創建均在ActivityThread中完成,我之前寫過一篇文章Android源碼分析-Activity的啟動過程,在文中我指出Activity啟動的核心過程是在ActivityThread中完成的,這裡要說明的是,Application和Service的創建也是在ActivityThread中完成的。下面我們看下三者在創建時是怎麼和ContextImpl相關聯的。
Activity對象中ContextImpl的創建
代碼為ActivityThread中的performLaunchActivity方法
可以看出,Activity在創建的時候會new一個ContextImpl對象並在attach方法中關聯它,需要注意的是,創建Activity使用的數據結構是ActivityClientRecord。
Application對象中ContextImpl的創建
代碼在ActivityThread中的handleBindApplication方法中,此方法內部調用了makeApplication方法
看代碼發現和Activity中ContextImpl的創建是相同的。
Service對象中ContextImpl的創建
通過查看代碼發現和Activity、Application是一致的。分析到這裡,那麼三者的Context有什麼區別呢?沒有區別嗎?盡管如此,有一些細節是確定的:Dialog的使用需要Activity,在桌面上我們采用Application的Context無法彈出對話框,同時在桌面上想啟動新的activity,我們需要為intent設置FLAG_ACTIVITY_NEW_TASK標志,否則無法啟動activity,這一切都說明,起碼Application的Context和Activity的Context還是有區別的,當然這也可能不是Context的區別,因為在桌面上,我們的應用沒有界面,這意味著我們能干的事情可能受到了限制,事情的細節目前我還沒有搞的很清楚。
很明確,不同的Context得到的都是同一份資源。這是很好理解的,請看下面的分析
得到資源的方式為context.getResources,而真正的實現位於ContextImpl中的getResources方法,在ContextImpl中有一個成員 private Resources mResources,它就是getResources方法返回的結果,mResources的賦值代碼為:
mResources = mResourcesManager.getTopLevelResources(mPackageInfo.getResDir(),
Display.DEFAULT_DISPLAY, null, compatInfo, activityToken);
下面看一下ResourcesManager的getTopLevelResources方法,這個方法的思想是這樣的:在ResourcesManager中,所有的資源對象都被存儲在ArrayMap中,首先根據當前的請求參數去查找資源,如果找到了就返回,否則就創建一個資源對象放到ArrayMap中。有一點需要說明的是為什麼會有多個資源對象,原因很簡單,因為res下可能存在多個適配不同設備、不同分辨率、不同系統版本的目錄,按照android系統的設計,不同設備在訪問同一個應用的時候訪問的資源可以不同,比如drawable-hdpi和drawable-xhdpi就是典型的例子。
根據上述代碼中資源的請求機制,再加上ResourcesManager采用單例模式,這樣就保證了不同的ContextImpl訪問的是同一套資源,注意,這裡說的同一套資源未必是同一個資源,因為資源可能位於不同的目錄,但它一定是我們的應用的資源,或許這樣來描述更准確,在設備參數和顯示參數不變的情況下,不同的ContextImpl訪問到的是同一份資源。設備參數不變是指手機的屏幕和android版本不變,顯示參數不變是指手機的分辨率和橫豎屏狀態。也就是說,盡管Application、Activity、Service都有自己的ContextImpl,並且每個ContextImpl都有自己的mResources成員,但是由於它們的mResources成員都來自於唯一的ResourcesManager實例,所以它們看似不同的mResources其實都指向的是同一塊內存(C語言的概念),因此,它們的mResources都是同一個對象(在設備參數和顯示參數不變的情況下)。在橫豎屏切換的情況下且應用中為橫豎屏狀態提供了不同的資源,處在橫屏狀態下的ContextImpl和處在豎屏狀態下的ContextImpl訪問的資源不是同一個資源對象。
代碼:單例模式的ResourcesManager類
getApplication返回結果為Application,且不同的Activity和Service返回的Application均為同一個全局對象,在ActivityThread內部有一個列表專門用於維護所有應用的application
final ArrayList mAllApplications = new ArrayList();
getApplicationContext返回的也是Application對象,只不過返回類型為Context,看看它的實現
上面代碼中mPackageInfo是包含當前應用的包信息、比如包名、應用的安裝目錄等,原則上來說,作為第三方應用,包信息mPackageInfo不可能為空,在這種情況下,getApplicationContext返回的對象和getApplication是同一個。但是對於系統應用,包信息有可能為空,具體就不深入研究了。從這種角度來說,對於第三方應用,一個應用只存在一個Application對象,且通過getApplication和getApplicationContext得到的是同一個對象,兩者的區別僅僅是返回類型不同。
到此已經很明了了,一個應用中Context的數量等於Activity的個數 + Service的個數 + 1,這個1為Application。
前言 在打開愛奇藝等app的歡迎界面的時候,右上角有一個倒計時的控件。倒計時完了以後進入主界面。現在我們來實現這個功能。 方法一:利用ja
很多品牌的Android手機都實現了圖案解鎖屏幕的功能,有些應用程序出於保護的目的也使用了圖案鎖(比如支付寶),本文將介紹一種圖案鎖的實現方式,這種實現的一個優勢在於方便
之前的文章一直在介紹OC,最近也是在找急忙慌的學習IOS,所以Android方面的知識分享就有點中斷了,但是我現在還是要靠Android吃飯,所以不能Android的工作
Android SDK快速接入信鴿推送信鴿平台注冊應用:創建後, 查看配置獲取AcessId和AcessKey信息工程配置配置jar包:配置jni相關文件:信鴿清單文件配