日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢(xún)
選擇下列產(chǎn)品馬上在線(xiàn)溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
Context都沒(méi)弄明白,還怎么做Android開(kāi)發(fā)?

Activity mActivity =new Activity()

成都創(chuàng)新互聯(lián)服務(wù)項(xiàng)目包括瑪沁網(wǎng)站建設(shè)、瑪沁網(wǎng)站制作、瑪沁網(wǎng)頁(yè)制作以及瑪沁網(wǎng)絡(luò)營(yíng)銷(xiāo)策劃等。多年來(lái),我們專(zhuān)注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢(shì)、行業(yè)經(jīng)驗(yàn)、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,瑪沁網(wǎng)站推廣取得了明顯的社會(huì)效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶(hù)以成都為中心已經(jīng)輻射到瑪沁省份的部分城市,未來(lái)相信會(huì)繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶(hù)的支持與信任!

作為Android開(kāi)發(fā)者,不知道你有沒(méi)有思考過(guò)這個(gè)問(wèn)題,Activity可以new嗎?Android的應(yīng)用程序開(kāi)發(fā)采用JAVA語(yǔ)言,Activity本質(zhì)上也是一個(gè)對(duì)象,那上面的寫(xiě)法有什么問(wèn)題呢?估計(jì)很多人說(shuō)不清道不明。Android程序不像Java程序一樣,隨便創(chuàng)建一個(gè)類(lèi),寫(xiě)個(gè)main()方法就能運(yùn)行,Android應(yīng)用模型是基于組件的應(yīng)用設(shè)計(jì)模式,組件的運(yùn)行要有一個(gè)完整的Android工程環(huán)境,在這個(gè)環(huán)境下,Activity、Service等系統(tǒng)組件才能夠正常工作,而這些組件并不能采用普通的Java對(duì)象創(chuàng)建方式,new一下就能創(chuàng)建實(shí)例了,而是要有它們各自的上下文環(huán)境,也就是我們這里討論的context??梢赃@樣講,Context是維持Android程序中各組件能夠正常工作的一個(gè)核心功能類(lèi)。

Context到底是什么

Context的中文翻譯為:語(yǔ)境; 上下文; 背景; 環(huán)境,在開(kāi)發(fā)中我們經(jīng)常說(shuō)稱(chēng)之為“上下文”,那么這個(gè)“上下文”到底是指什么意思呢?在語(yǔ)文中,我們可以理解為語(yǔ)境,在程序中,我們可以理解為當(dāng)前對(duì)象在程序中所處的一個(gè)環(huán)境,一個(gè)與系統(tǒng)交互的過(guò)程。比如微信聊天,此時(shí)的“環(huán)境”是指聊天的界面以及相關(guān)的數(shù)據(jù)請(qǐng)求與傳輸,Context在加載資源、啟動(dòng)Activity、獲取系統(tǒng)服務(wù)、創(chuàng)建View等操作都要參與。

那Context到底是什么呢?一個(gè)Activity就是一個(gè)Context,一個(gè)Service也是一個(gè)Context。Android程序員把“場(chǎng)景”抽象為Context類(lèi),他們認(rèn)為用戶(hù)和操作系統(tǒng)的每一次交互都是一個(gè)場(chǎng)景,比如打電話(huà)、發(fā)短信,這些都是一個(gè)有界面的場(chǎng)景,還有一些沒(méi)有界面的場(chǎng)景,比如后臺(tái)運(yùn)行的服務(wù)(Service)。一個(gè)應(yīng)用程序可以認(rèn)為是一個(gè)工作環(huán)境,用戶(hù)在這個(gè)環(huán)境中會(huì)切換到不同的場(chǎng)景,這就像一個(gè)前臺(tái)秘書(shū),她可能需要接待客人,可能要打印文件,還可能要接聽(tīng)客戶(hù)電話(huà),而這些就稱(chēng)之為不同的場(chǎng)景,前臺(tái)秘書(shū)可以稱(chēng)之為一個(gè)應(yīng)用程序。

如何生動(dòng)形象的理解Context

上面的概念中采用了通俗的理解方式,將Context理解為“上下文”或者“場(chǎng)景”,如果你仍然覺(jué)得很抽象,不好理解。在這里我給出一個(gè)可能不是很恰當(dāng)?shù)谋扔?,希望有助于大家的理解:一個(gè)Android應(yīng)用程序,可以理解為一部電影或者一部電視劇,Activity,Service,Broadcast Receiver,Content Provider這四大組件就好比是這部戲里的四個(gè)主角:胡歌,霍建華,詩(shī)詩(shī),Baby。他們是由劇組(系統(tǒng))一開(kāi)始就定好了的,整部戲就是由這四位主演領(lǐng)銜擔(dān)綱的,所以這四位主角并不是大街上隨隨便便拉個(gè)人(new 一個(gè)對(duì)象)都能演的。有了演員當(dāng)然也得有攝像機(jī)拍攝啊,他們必須通過(guò)鏡頭(Context)才能將戲傳遞給觀眾,這也就正對(duì)應(yīng)說(shuō)四大組件(四位主角)必須工作在Context環(huán)境下(攝像機(jī)鏡頭)。那Button,TextView,LinearLayout這些控件呢,就好比是這部戲里的配角或者說(shuō)群眾演員,他們顯然沒(méi)有這么重用,隨便一個(gè)路人甲路人乙都能演(可以new一個(gè)對(duì)象),但是他們也必須要面對(duì)鏡頭(工作在Context環(huán)境下),所以Button mButton=new Button(Context)是可以的。雖然不很恰當(dāng),但還是很容易理解的,希望有幫助。

源碼中的Context

 
 
 
 
  1. /** 
  2. * Interface to global information about an application environment.  This is 
  3. * an abstract class whose implementation is provided by 
  4. * the Android system.  It 
  5. * allows access to application-specific resources and classes, as well as 
  6. * up-calls for application-level operations such as launching activities, 
  7. * broadcasting and receiving intents, etc. 
  8. */ 
  9. public abstract class Context { 
  10.     /** 
  11.      * File creation mode: the default mode, where the created file can only 
  12.      * be accessed by the calling application (or all applications sharing the 
  13.      * same user ID). 
  14.      * @see #MODE_WORLD_READABLE 
  15.      * @see #MODE_WORLD_WRITEABLE 
  16.      */ 
  17.     public static final int MODE_PRIVATE = 0x0000; 
  18.   
  19.     public static final int MODE_WORLD_WRITEABLE = 0x0002; 
  20.   
  21.     public static final int MODE_APPEND = 0x8000; 
  22.   
  23.     public static final int MODE_MULTI_PROCESS = 0x0004; 
  24.   
  25.     . 
  26.     . 
  27.     . 
  28.     }  

源碼中的注釋是這么來(lái)解釋Context的:Context提供了關(guān)于應(yīng)用環(huán)境全局信息的接口。它是一個(gè)抽象類(lèi),它的執(zhí)行被Android系統(tǒng)所提供。它允許獲取以應(yīng)用為特征的資源和類(lèi)型,是一個(gè)統(tǒng)領(lǐng)一些資源(應(yīng)用程序環(huán)境變量等)的上下文。就是說(shuō),它描述一個(gè)應(yīng)用程序環(huán)境的信息(即上下文);是一個(gè)抽象類(lèi),Android提供了該抽象類(lèi)的具體實(shí)現(xiàn)類(lèi);通過(guò)它我們可以獲取應(yīng)用程序的資源和類(lèi)(包括應(yīng)用級(jí)別操作,如啟動(dòng)Activity,發(fā)廣播,接受Intent等)。既然上面Context是一個(gè)抽象類(lèi),那么肯定有他的實(shí)現(xiàn)類(lèi)咯,我們?cè)贑ontext的源碼中通過(guò)IDE可以查看到他的子類(lèi)最終可以得到如下圖:  

Context.png

Context類(lèi)本身是一個(gè)純abstract類(lèi),它有兩個(gè)具體的實(shí)現(xiàn)子類(lèi):ContextImpl和ContextWrapper。其中ContextWrapper類(lèi),如其名所言,這只是一個(gè)包裝而已,ContextWrapper構(gòu)造函數(shù)中必須包含一個(gè)真正的Context引用,同時(shí)ContextWrapper中提供了attachBaseContext()用于給ContextWrapper對(duì)象中指定真正的Context對(duì)象,調(diào)用ContextWrapper的方法都會(huì)被轉(zhuǎn)向其所包含的真正的Context對(duì)象。ContextThemeWrapper類(lèi),如其名所言,其內(nèi)部包含了與主題(Theme)相關(guān)的接口,這里所說(shuō)的主題就是指在AndroidManifest.xml中通過(guò)android:theme為Application元素或者Activity元素指定的主題。當(dāng)然,只有Activity才需要主題,Service是不需要主題的,因?yàn)镾ervice是沒(méi)有界面的后臺(tái)場(chǎng)景,所以Service直接繼承于ContextWrapper,Application同理。而ContextImpl類(lèi)則真正實(shí)現(xiàn)了Context中的所以函數(shù),應(yīng)用程序中所調(diào)用的各種Context類(lèi)的方法,其實(shí)現(xiàn)均來(lái)自于該類(lèi)。一句話(huà)總結(jié):Context的兩個(gè)子類(lèi)分工明確,其中ContextImpl是Context的具體實(shí)現(xiàn)類(lèi),ContextWrapper是Context的包裝類(lèi)。Activity,Application,Service雖都繼承自ContextWrapper(Activity繼承自ContextWrapper的子類(lèi)ContextThemeWrapper),但它們初始化的過(guò)程中都會(huì)創(chuàng)建ContextImpl對(duì)象,由ContextImpl實(shí)現(xiàn)Context中的方法。

一個(gè)應(yīng)用程序有幾個(gè)Context

其實(shí)這個(gè)問(wèn)題本身并沒(méi)有什么意義,關(guān)鍵還是在于對(duì)Context的理解,從上面的關(guān)系圖我們已經(jīng)可以得出答案了,在應(yīng)用程序中Context的具體實(shí)現(xiàn)子類(lèi)就是:Activity,Service,Application。那么Context數(shù)量=Activity數(shù)量+Service數(shù)量+1。當(dāng)然如果你足夠細(xì)心,可能會(huì)有疑問(wèn):我們常說(shuō)四大組件,這里怎么只有Activity,Service持有Context,那Broadcast Receiver,Content Provider呢?Broadcast Receiver,Content Provider并不是Context的子類(lèi),他們所持有的Context都是其他地方傳過(guò)去的,所以并不計(jì)入Context總數(shù)。上面的關(guān)系圖也從另外一個(gè)側(cè)面告訴我們Context類(lèi)在整個(gè)Android系統(tǒng)中的地位是多么的崇高,因?yàn)楹茱@然Activity,Service,Application都是其子類(lèi),其地位和作用不言而喻。

Context能干什么

Context到底可以實(shí)現(xiàn)哪些功能呢?這個(gè)就實(shí)在是太多了,彈出Toast、啟動(dòng)Activity、啟動(dòng)Service、發(fā)送廣播、操作數(shù)據(jù)庫(kù)等等都需要用到Context。

 
 
 
 
  1. TextView tv = new TextView(getContext()); 
  2.   
  3. ListAdapter adapter = new SimpleCursorAdapter(getApplicationContext(), ...); 
  4.   
  5. AudioManager am = (AudioManager)getContext().getSystemService(Context.AUDIO_SERVICE);getApplicationContext().getSharedPreferences(name, mode); 
  6.   
  7. getApplicationContext().getContentResolver().query(uri, ...); 
  8.   
  9. getContext().getResources().getDisplayMetrics().widthPixels * 5 / 8; 
  10.   
  11. getContext().startActivity(intent); 
  12.   
  13. getContext().startService(intent); 
  14.   
  15. getContext().sendBroadcast(intent);  

Context作用域

雖然Context神通廣大,但并不是隨便拿到一個(gè)Context實(shí)例就可以為所欲為,它的使用還是有一些規(guī)則限制的。由于Context的具體實(shí)例是由ContextImpl類(lèi)去實(shí)現(xiàn)的,因此在絕大多數(shù)場(chǎng)景下,Activity、Service和Application這三種類(lèi)型的Context都是可以通用的。不過(guò)有幾種場(chǎng)景比較特殊,比如啟動(dòng)Activity,還有彈出Dialog。出于安全原因的考慮,Android是不允許Activity或Dialog憑空出現(xiàn)的,一個(gè)Activity的啟動(dòng)必須要建立在另一個(gè)Activity的基礎(chǔ)之上,也就是以此形成的返回棧。而Dialog則必須在一個(gè)Activity上面彈出(除非是System Alert類(lèi)型的Dialog),因此在這種場(chǎng)景下,我們只能使用Activity類(lèi)型的Context,否則將會(huì)出錯(cuò)。 

 

 

 

Context作用域.png

從上圖我們可以發(fā)現(xiàn)Activity所持有的Context的作用域最廣,無(wú)所不能。因?yàn)锳ctivity繼承自ContextThemeWrapper,而Application和Service繼承自ContextWrapper,很顯然ContextThemeWrapper在ContextWrapper的基礎(chǔ)上又做了一些操作使得Activity變得更強(qiáng)大,這里我就不再貼源碼給大家分析了,有興趣的童鞋可以自己查查源碼。上圖中的YES和NO我也不再做過(guò)多的解釋了,這里我說(shuō)一下上圖中Application和Service所不推薦的兩種使用情況。

1:如果我們用ApplicationContext去啟動(dòng)一個(gè)LaunchMode為standard的Activity的時(shí)候會(huì)報(bào)錯(cuò)android.util.AndroidRuntimeException: Calling startActivity from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?這是因?yàn)榉茿ctivity類(lèi)型的Context并沒(méi)有所謂的任務(wù)棧,所以待啟動(dòng)的Activity就找不到棧了。解決這個(gè)問(wèn)題的方法就是為待啟動(dòng)的Activity指定FLAG_ACTIVITY_NEW_TASK標(biāo)記位,這樣啟動(dòng)的時(shí)候就為它創(chuàng)建一個(gè)新的任務(wù)棧,而此時(shí)Activity是以singleTask模式啟動(dòng)的。所有這種用Application啟動(dòng)Activity的方式不推薦使用,Service同Application。

2:在Application和Service中去layout inflate也是合法的,但是會(huì)使用系統(tǒng)默認(rèn)的主題樣式,如果你自定義了某些樣式可能不會(huì)被使用。所以這種方式也不推薦使用。

一句話(huà)總結(jié):凡是跟UI相關(guān)的,都應(yīng)該使用Activity做為Context來(lái)處理;其他的一些操作,Service,Activity,Application等實(shí)例都可以,當(dāng)然了,注意Context引用的持有,防止內(nèi)存泄漏。

如何獲取Context

通常我們想要獲取Context對(duì)象,主要有以下四種方法:

1:View.getContext,返回當(dāng)前View對(duì)象的Context對(duì)象,通常是當(dāng)前正在展示的Activity對(duì)象。

2:Activity.getApplicationContext,獲取當(dāng)前Activity所在的(應(yīng)用)進(jìn)程的Context對(duì)象,通常我們使用Context對(duì)象時(shí),要優(yōu)先考慮這個(gè)全局的進(jìn)程Context。

3:ContextWrapper.getBaseContext():用來(lái)獲取一個(gè)ContextWrapper進(jìn)行裝飾之前的Context,可以使用這個(gè)方法,這個(gè)方法在實(shí)際開(kāi)發(fā)中使用并不多,也不建議使用。

4:Activity.this 返回當(dāng)前的Activity實(shí)例,如果是UI控件需要使用Activity作為Context對(duì)象,但是默認(rèn)的Toast實(shí)際上使用ApplicationContext也可以。

getApplication()和getApplicationContext()

上面說(shuō)到獲取當(dāng)前Application對(duì)象用getApplicationContext,不知道你有沒(méi)有聯(lián)想到getApplication(),這兩個(gè)方法有什么區(qū)別?相信這個(gè)問(wèn)題會(huì)難倒不少開(kāi)發(fā)者。 

 

 

 

getApplication()&getApplicationContext().png

程序是不會(huì)騙人的,我們通過(guò)上面的代碼,打印得出兩者的內(nèi)存地址都是相同的,看來(lái)它們是同一個(gè)對(duì)象。其實(shí)這個(gè)結(jié)果也很好理解,因?yàn)榍懊嬉呀?jīng)說(shuō)過(guò)了,Application本身就是一個(gè)Context,所以這里獲取getApplicationContext()得到的結(jié)果就是Application本身的實(shí)例。那么問(wèn)題來(lái)了,既然這兩個(gè)方法得到的結(jié)果都是相同的,那么Android為什么要提供兩個(gè)功能重復(fù)的方法呢?

實(shí)際上這兩個(gè)方法在作用域上有比較大的區(qū)別。getApplication()方法的語(yǔ)義性非常強(qiáng),一看就知道是用來(lái)獲取Application實(shí)例的,但是這個(gè)方法只有在Activity和Service中才能調(diào)用的到。那么也許在絕大多數(shù)情況下我們都是在Activity或者Service中使用Application的,但是如果在一些其它的場(chǎng)景,比如BroadcastReceiver中也想獲得Application的實(shí)例,這時(shí)就可以借助getApplicationContext()方法了。

 
 
 
 
  1. publicclassMyReceiverextendsBroadcastReceiver{ 
  2.   
  3. @Override 
  4. publicvoidonReceive(Contextcontext,Intentintent){ 
  5. ApplicationmyApp=(Application)context.getApplicationContext(); 
  6.   
  7.   
  8. }  

Context引起的內(nèi)存泄露

但Context并不能隨便亂用,用的不好有可能會(huì)引起內(nèi)存泄露的問(wèn)題,下面就示例兩種錯(cuò)誤的引用方式。

錯(cuò)誤的單例模式

 
 
 
 
  1. public class Singleton { 
  2.     private static Singleton instance; 
  3.     private Context mContext; 
  4.   
  5.     private Singleton(Context context) { 
  6.         this.mContext = context; 
  7.     } 
  8.   
  9.     public static Singleton getInstance(Context context) { 
  10.         if (instance == null) { 
  11.             instance = new Singleton(context); 
  12.         } 
  13.         return instance; 
  14.     } 
  15. }  

這是一個(gè)非線(xiàn)程安全的單例模式,instance作為靜態(tài)對(duì)象,其生命周期要長(zhǎng)于普通的對(duì)象,其中也包含Activity,假如Activity A去getInstance獲得instance對(duì)象,傳入this,常駐內(nèi)存的Singleton保存了你傳入的Activity A對(duì)象,并一直持有,即使Activity被銷(xiāo)毀掉,但因?yàn)樗囊眠€存在于一個(gè)Singleton中,就不可能被GC掉,這樣就導(dǎo)致了內(nèi)存泄漏。

View持有Activity引用

 
 
 
 
  1. public class MainActivity extends Activity { 
  2.     private static Drawable mDrawable; 
  3.   
  4.     @Override 
  5.     protected void onCreate(Bundle saveInstanceState) { 
  6.         super.onCreate(saveInstanceState); 
  7.         setContentView(R.layout.activity_main); 
  8.         ImageView iv = new ImageView(this); 
  9.         mDrawable = getResources().getDrawable(R.drawable.ic_launcher); 
  10.         iv.setImageDrawable(mDrawable); 
  11.     } 
  12. }  

有一個(gè)靜態(tài)的Drawable對(duì)象當(dāng)ImageView設(shè)置這個(gè)Drawable時(shí),ImageView保存了mDrawable的引用,而ImageView傳入的this是MainActivity的mContext,因?yàn)楸籹tatic修飾的mDrawable是常駐內(nèi)存的,MainActivity是它的間接引用,MainActivity被銷(xiāo)毀時(shí),也不能被GC掉,所以造成內(nèi)存泄漏。

正確使用Context

一般Context造成的內(nèi)存泄漏,幾乎都是當(dāng)Context銷(xiāo)毀的時(shí)候,卻因?yàn)楸灰脤?dǎo)致銷(xiāo)毀失敗,而Application的Context對(duì)象可以理解為隨著進(jìn)程存在的,所以我們總結(jié)出使用Context的正確姿勢(shì):

1:當(dāng)Application的Context能搞定的情況下,并且生命周期長(zhǎng)的對(duì)象,優(yōu)先使用Application的Context。

2:不要讓生命周期長(zhǎng)于Activity的對(duì)象持有到Activity的引用。

3:盡量不要在Activity中使用非靜態(tài)內(nèi)部類(lèi),因?yàn)榉庆o態(tài)內(nèi)部類(lèi)會(huì)隱式持有外部類(lèi)實(shí)例的引用,如果使用靜態(tài)內(nèi)部類(lèi),將外部實(shí)例引用作為弱引用持有。

總結(jié)

總之Context在Android系統(tǒng)中的地位很重要,它幾乎無(wú)所不能,但它也不是你想用就能隨便用的,謹(jǐn)防使用不當(dāng)引起的內(nèi)存問(wèn)題。如果還有疑問(wèn)或者想了解更多內(nèi)容,可以去看我的:視頻課程


分享文章:Context都沒(méi)弄明白,還怎么做Android開(kāi)發(fā)?
路徑分享:http://www.5511xx.com/article/djhdgge.html