JAVA中Context的詳細(xì)介紹和實(shí)例分析
最熟悉的陌生人——Context
剛剛學(xué)android或者js等,都會(huì)看見(jiàn)這個(gè)頻繁的字眼——Context。
意為”上下文“。
本文主要記述,Context到底是什么、如何理解Context、一個(gè)APP可以有幾個(gè)Context、Context能干啥、Context的作用域、獲取Context、全局獲取Context技巧。
思考:
Java:萬(wàn)物皆對(duì)象。Flutter:萬(wàn)物皆組件。
俗語(yǔ):”沒(méi)對(duì)象嗎?自己new一個(gè)啊~“
既然大多數(shù)情況可以new一個(gè)實(shí)例,那么,我們?cè)赼ndroid中的Activity實(shí)例怎么獲取呢?Activity.instance可以獲取activity。既然Activity也大致歸屬于一個(gè)類(lèi),那么可不可以用 Activity activity=new Activity(); 呢?安卓不像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.
所以說(shuō),Context是維持android各組件能夠正常工作的一個(gè)核心功能類(lèi)。
what 's Context:
(本圖為沙拉查詞給出的中文翻譯)
有點(diǎn)晦澀難懂。但在程序中,我們可理解為當(dāng)前對(duì)象在程序中所處的一個(gè)環(huán)境,一個(gè)與系統(tǒng)交互的過(guò)程。 比如QQ和你們自己的女朋友聊天時(shí)(沒(méi)有g(shù)rilfriend的可自己跳過(guò)舉例),此時(shí)的context是指的聊天界面以及相關(guān)的數(shù)據(jù)請(qǐng)求與傳輸,Context在加載資源、啟動(dòng)Activity、獲取系統(tǒng)服務(wù)、創(chuàng)建View等操作都要參與。
所以,一個(gè)Activity就是一個(gè)Context(getActivity()==getContext),一個(gè)Service也是一個(gè)Context。Android把場(chǎng)景抽象為Context類(lèi),用戶和操作系統(tǒng)的每一次交互都是一個(gè)場(chǎng)景,比如:打電話、發(fā)短信等,都有activity,還有一些我們?nèi)庋劭床灰?jiàn)的后臺(tái)服務(wù)。一個(gè)應(yīng)用程序可以認(rèn)為是一個(gè)工作環(huán)境,用戶在這個(gè)環(huán)境中切換到不同的場(chǎng)景,這就像服務(wù)員,客戶可能是外賣(mài)小哥、也可能是農(nóng)民工等,這些就是不同的場(chǎng)景,而服務(wù)員就是一個(gè)應(yīng)用程序。
How to understand the ‘Context':
Context理解為”上下文“/”場(chǎng)景“,可能還是很抽象。那么我們可以做一個(gè)比喻:
一個(gè)APP是仙劍奇?zhèn)b傳3電視劇,Activity、Service、BroadcastReceiver、ContentProvider這四大組件就是電視劇的主角。它們是導(dǎo)演(系統(tǒng))一開(kāi)始就確定好試鏡成功的人。換言之, 不是我們每個(gè)人都能被導(dǎo)演認(rèn)可的。有了演員,就要有鏡頭啊,這個(gè)鏡頭便是(Context)。通過(guò)鏡頭,我們才能看見(jiàn)帥氣 的胡歌。演員們都是在鏡頭(Context環(huán)境)下表演的。那么Button這些組件子類(lèi)型就是配角,它們沒(méi)有那么重要,隨便一個(gè)組件都能參與演出(即隨便new 一個(gè)實(shí)例),但是它們也需要參與鏡頭,不然一部戲只有主角多沒(méi)意思,魔尊重樓還是要的,魔尊也要露面(工作在Context環(huán)境下),所以可以用代碼new Button();或者xml布局定義一個(gè)button。
打開(kāi)AndroidStudio,輸入Context,然后ctrl+鼠標(biāo)左鍵追朔其源碼(看源碼一般都先看注釋便于理解):import android.content.Context;
看注釋?zhuān)琓MD,是English,那么筆者這里就用小學(xué)生英語(yǔ)水平來(lái)翻譯一哈哈:
Context提供了關(guān)于應(yīng)用環(huán)境全局信息的接口。它是一個(gè)abstract類(lèi),它的執(zhí)行被Android系統(tǒng)提供,允許獲取以應(yīng)用為特征的資源和類(lèi)型,是一個(gè)統(tǒng)領(lǐng)一些資源APP環(huán)境變量等的上下文。通過(guò)它可以獲取應(yīng)用程序的資源和類(lèi)(包括應(yīng)用級(jí)別操作,如啟動(dòng)Activity,發(fā)廣播,接收intent等)。abstract會(huì)有它的實(shí)現(xiàn)類(lèi)。在源碼中,我們可以通過(guò)AndroidStudio去查看它的子類(lèi),得到以下關(guān)系:
它有2個(gè)具體實(shí)現(xiàn)子類(lèi):ContextImpl、ContextWrapper。
- 其中,ContextWrapper類(lèi),只是一個(gè)包裝類(lèi),其構(gòu)造函數(shù)中必須包含一個(gè)Context引用,同時(shí)它提供了attachBaseContext()用于給ContextWrapper對(duì)象中指定真正的Context對(duì)象,調(diào)用它的方法都會(huì)被轉(zhuǎn)向其所包含的真正的Context對(duì)象。
- ContextThemeWrapper類(lèi)其內(nèi)部包含了與主題相關(guān)的接口。主題就是清單文件中android:theme為Application或Activity元素指定的主題。(Activity才需要主題,Serviceu不需要,因?yàn)榉?wù)是沒(méi)有界面的后臺(tái)場(chǎng)景,所以服務(wù)直接繼承ContextWrapper。Application同理。)而Contextlmpl類(lèi)則是真正實(shí)現(xiàn)了Context中的所有函數(shù),應(yīng)用程序中所調(diào)用的各種Context類(lèi)的方法,其實(shí)現(xiàn)均來(lái)自這個(gè)類(lèi)。
- 換言之:Context的2個(gè)實(shí)現(xiàn)子類(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中的方法。
How much has Context in a App:
關(guān)鍵在于對(duì)COntext的理解。從上面提到的實(shí)現(xiàn)子類(lèi)可以看出,在APP中,Context的具體實(shí)現(xiàn)子類(lèi)是Acitivity、Service、Applicaiton。所以Context's number=Activity's number + Service's number+1(1個(gè)APP只有一個(gè)Application)。為啥不是4大組件,上面不是說(shuō)四大組件也是主角嗎?看看BroadcastReceiver和ContentProvider的源碼可以知道它們并不是Context的子類(lèi),它們持有的Context都是其他地方傳遞過(guò)去的(比如我們發(fā)送廣播intent中的context就是外部傳遞過(guò)來(lái)的),所以不計(jì)數(shù)它們。
Context's method:
Context哪里會(huì)用到它。剛開(kāi)始了解Android的時(shí)候不知道它是個(gè)啥玩意兒,但是久了發(fā)現(xiàn)有些地方就不得不傳這個(gè)參數(shù)。
比如Toast、啟動(dòng)Activity、啟動(dòng)Service、發(fā)送廣播、操作數(shù)據(jù)庫(kù)等等都需要傳Context參數(shù),具體例子就不說(shuō)了。詳細(xì)可以看后文將提到的如何獲取它。
Context's 作用域
不是隨便獲取一個(gè)Context實(shí)例就可以的,它的使用有一些規(guī)則和限制。因?yàn)镃ontext的具體實(shí)例是由ContextImpl類(lèi)去實(shí)現(xiàn)的,因此,Activity、Service、Application3種類(lèi)型的Context都是等價(jià)的。但是,需要注意的是,,有些場(chǎng)景,比如啟動(dòng)Activity、彈出Dialog等。為了安全,Android不允許Activity或者Dialog憑空出現(xiàn),一個(gè)Activity的啟動(dòng)肯定是由另一個(gè)Activity負(fù)責(zé)的,也就是以此形成的返回棧(具體可以看看任主席的《Android開(kāi)發(fā)藝術(shù)探索》)而Dialog則必須是在一個(gè)Activity上彈出(系統(tǒng)Alert類(lèi)型的Dialog除外),這種情況下, 我們只能用Activity類(lèi)型的Context,否則報(bào)錯(cuò)。
Context作用域 | Application | Activity | Service |
---|---|---|---|
Show a Dialog | No | Yes | No |
Start an Activity | 不推薦 | Yes | 不推薦 |
Layout Inflation | 不推薦 | Yes | 不推薦 |
Start a Service | Yes | Yes | Yes |
Send a Broadcast | Yes | Yes | Yes |
Register Broadcast Receiver | Yes | Yes | Yes |
Load Resource Values | Yes | Yes | Yes |
Activity繼承自ContextThemeWrapper,而Application和Service繼承ContextWrapper,所以ContextThemeWrapper在ContextWrapper的基礎(chǔ)上作了一些操作,使得Activity更加厲害。
關(guān)于表格中提到的Application和Service不推薦的2種情況:
1.如果用ApplicationContext去啟動(dòng)一個(gè)LaunchMode為standard的Activity的時(shí)候會(huì)報(bào)錯(cuò):androud,util.AndroidRuntimeException:Calling startActivity from outside of an Activity context require the FLAG_ACTIVITY_NEW_TASK flag。Is this really what you want?
翻譯一下,并了解這個(gè)FLAG的都知道,此時(shí)的非Activity類(lèi)型的Context并沒(méi)有所謂的返回棧,因此帶啟動(dòng)的Activity就找不到棧。它還給我們明確之處了FLAG的解決辦法,這樣啟動(dòng)的時(shí)候就為它創(chuàng)建一個(gè)新的任務(wù)棧,而此時(shí)Activity是以Single Task模式啟動(dòng)的。所以這種用Application Context啟動(dòng)Activity的方式不推薦,Service同理。
2.在Application和Service中去layout inflate也是合法的,但是會(huì)使用系統(tǒng)默認(rèn)的主題樣式,如果自定義了某些樣式可能不會(huì)被使用,所以也不推薦。
注:和UI相關(guān)的,都應(yīng)該使用Activity Context來(lái)處理。其他的一些操作,Service、Activity、Application等實(shí)例都是可以的。同時(shí)要注意Context的引用持有,防止內(nèi)存泄漏。可在被銷(xiāo)毀的時(shí)候,置Context為null。
How to get the ‘Context':
常用4種方法獲取Context對(duì)象:
1.View.getContext():返回當(dāng)前View對(duì)象的Context對(duì)象。通常是當(dāng)前正在展示的Activity對(duì)象。
1.Activity,getApplicationContext()[后文會(huì)詳細(xì)介紹這個(gè)方法]:獲取當(dāng)前Activity所在應(yīng)用進(jìn)程的Context對(duì)象,通常我們使用3.Context對(duì)象時(shí),要優(yōu)先考慮這個(gè)全局的進(jìn)程Context。
ContextWrapper.getBaseContext():用來(lái)獲取一個(gè)ContextWrapper進(jìn)行裝飾之前的Context。實(shí)際開(kāi)發(fā)很少用,也不建議使用。
4.Activity.this:返回當(dāng)前Activity的實(shí)例,如果的UI控件需要使用Activity作為Context對(duì)象,但默認(rèn)的Toast實(shí)際上使用的ApplicationContext也可以。
實(shí)現(xiàn)View.OnClick監(jiān)聽(tīng)方法中,寫(xiě)Toast,不要用this,因?yàn)閠his,在onClick(View view)指的是view對(duì)象而不是Activity實(shí)例,所以在這個(gè)方法中,應(yīng)該使用”當(dāng)前的Activity名.this“,這是入門(mén)者比較容易混淆的地方。
getApplication()和getApplicationContext():
獲取當(dāng)前Application對(duì)象用getApplicationContext.但是getApplication又是什么。
我們可以自己寫(xiě)代碼打印一下:
Application app=(Application)getApplication(); Log.e(TAG,"getApplication is "+app); Context context=getApplicationContext(); Log.e(TAG,"getApplicationContext is "+ context);
運(yùn)行后看logcat,效果圖就不貼了(電腦卡)。從打印結(jié)果可以看出它們2個(gè)的內(nèi)存地址是相同的,即它們是同一個(gè)對(duì)象。 因?yàn)锳pplication本來(lái)就是一個(gè)Context,那么這里獲取的getApplicationContext()自然也是Application本身的實(shí)例了。那這2個(gè)相同方法存在的意義是啥?(雙胞胎?)實(shí)際上這2個(gè)方法在作用域上有比較大的區(qū)別。 getApplication()一看就知道是用來(lái)獲取Application實(shí)例的(道理可以聯(lián)想getActivity())。但getApplication()只有在Activity和Service中才能調(diào)用的到。 對(duì)于比如BroadcastReceiver等中也想要獲取Application實(shí)例,這時(shí)就需要getApplicationContext()方法。
//繼承BroadcastReceiver并重寫(xiě)onReceive()方法 @Override public void onReceive(Context context.Intent intent){ Application app=(Application)context.getApplicationContext(); }
內(nèi)存泄漏之Context:
我們經(jīng)常會(huì)遇到內(nèi)存泄漏,比如Activity銷(xiāo)毀了,但是Context還持有該Activity的引用,造成了內(nèi)存泄漏。(經(jīng)常遇到)
2種典型的錯(cuò)誤引用方式:
1.錯(cuò)誤的單例模式:
public class Singleton{ private static Singleton instancel private Context context; private Singleton(Context context){ this.context=context; } public static Singleton getInstance(Context context){ if(instance == null ){ instance=new Singleton(context); } return instance; } }
熟悉單例模式的都知道,這是一個(gè)非線程安全的單例模式,instance作為靜態(tài)對(duì)象,其生命周期要長(zhǎng)于普通的對(duì)象(單例直到APP退出后臺(tái)才銷(xiāo)毀),其中也包含了Activity。比如Activity A去getInstance()得到instance對(duì)象,傳入this,常駐內(nèi)存的Singleton保存了我們傳入的A對(duì)象,并一直持有,即使Activity被銷(xiāo)毀掉,但因?yàn)樗囊眠€存在于一個(gè)Singleton中,就不可能被GC掉,這樣就導(dǎo)致了內(nèi)存泄漏。比如典型的數(shù)據(jù)庫(kù)操作,存儲(chǔ)數(shù)據(jù),需要重復(fù)的去索取數(shù)據(jù),用單例保持?jǐn)?shù)據(jù)和拿到Activity持有context引用,因?yàn)閱卫梢钥醋魇巧系?,它幫我們保存?shù)據(jù)。所以即使Activity被finish掉,還有它的引用在Singleton中。
View持有Activity引用:
public class MainActivity extend Activity{ private static Drawable mDrawable; @Override protected void onCreate(Bundle saveInstanceState){ super.onCreate(); setContentView(R.layout.activity_main); ImageView imageview=new ImageView(this);//通過(guò)代碼動(dòng)態(tài)的創(chuàng)建組件,而不是傳統(tǒng)的xml配置組件,這里的ImageView持有當(dāng)前Activity的引用。 mDrawable=getResources().getDrawable(R.drawable.ic_launcher); imageview.setImageDrawable(mDrawable); } }
上述代碼中,有一個(gè)static的Drawable對(duì)象。當(dāng)ImageView設(shè)置這個(gè)Drawable的時(shí)候,ImageView保存了這個(gè)mDrawable的引用,而ImageView初始化的時(shí)候又傳入了this,此處的this是指MainActivity的context。因?yàn)楸籹tatic修飾的mDrawable是常駐內(nèi)存的(比類(lèi)還要早加載)。MainActivity是它的間接引用了,當(dāng)MainActivity被銷(xiāo)毀的時(shí)候,也不能被GC掉,就造成了內(nèi)存泄漏。
How to get the context in the whole :
大量的地方都需要使用Context,我們常常會(huì)因?yàn)椴恢涝趺吹玫竭@個(gè)Context而苦惱。那么,全局獲取Context無(wú)疑是最好的解決方案。
很多時(shí)候,我們也不是經(jīng)常為得不到Context而發(fā)愁,畢竟我們很多的操作都是在活動(dòng)中進(jìn)行的,而活動(dòng)本身就是一個(gè)Context對(duì)象。但APP架構(gòu)復(fù)雜后,很多邏輯代碼都脫離了Activity類(lèi),此時(shí)又需要使用Context,所以我們需要采取全局獲取Context的方法。
舉例, 我們平常經(jīng)常會(huì)寫(xiě)網(wǎng)絡(luò)工具類(lèi),比如下面的這些代碼:
public calss HttpUtil{ public static void sendHttpRequest(final String address,final HttpCallbackListener listener){ new Thread(new Runnable()){ @Override public void run(){ HttpURLConnection connection=null; try{ URL url =new URL(address); connection=(HttpURLConnection)url.openConnection(); connection.setRequestMethod("GET"); connection.setConnectTimeout(8000); connection.setReadTimeout(8000); connection.setDoInput(true); connection.setDoOutput(true); InputStream in =connection.getInputStream(); BufferedReader reader=new BufferedReader(new InputStreamReader(in)); StringBuilder response=new StringBuilder(); String line; while((line=reader.readLine())!=nulll){ response.append(line); } if(listener!=null){ //回調(diào)onFinish() listener.onFinish(response.toString); } }catch(Execption e){ if(listener!=null){ //回調(diào)onError() listener.onError(e); } }finally{ if(connection!=null){ connection.disconnect(); } } }}.start(); } }
上述代碼中使用sendHttpRequest()方法來(lái)發(fā)送HTTP請(qǐng)求顯然沒(méi)問(wèn)題。并且還可以在回調(diào)方法中處理服務(wù)器返回的數(shù)據(jù)。但是這個(gè)方法還可以被優(yōu)化。當(dāng)檢測(cè)不到網(wǎng)絡(luò)存在的時(shí)候就給用戶一個(gè)Toast,并不再執(zhí)行后面的代碼。問(wèn)題來(lái)了,Toast需要一個(gè)Context參數(shù),但是在本來(lái)沒(méi)有可以傳遞的Context對(duì)象。。。
一般思路:在方法中添加一個(gè)COntext參數(shù):
public static void sendHttpRequest(final String address,final HttpCallbackListener listener,final Context context){ if(!isNetWorkAvailable()){ Toast.makeText(context,……); …… } ……
看似可以,但是有點(diǎn)甩鍋。我們將獲取Context的任務(wù)轉(zhuǎn)移到了sendHttpRequest()方法的調(diào)用方。至于調(diào)用方能不能得到COntext對(duì)象就不是我們要考慮的問(wèn)題了。
甩鍋不一定是通用的解決方案。于是這里介紹哈如何獲取全局Context的步驟:,通過(guò)它在項(xiàng)目的任何地方都能輕松的獲取到Context。:
Android提供了一個(gè)Application類(lèi),每當(dāng)APP啟動(dòng)的時(shí)候,系統(tǒng)就會(huì)自動(dòng)將這個(gè)類(lèi)進(jìn)行初始化。我們可以定制一個(gè)自己的Application類(lèi),以便管理程序內(nèi)一些全局的狀態(tài)信息,比如說(shuō)全局Context。
定制一個(gè)自己的Application并不復(fù)雜,首先, 需要?jiǎng)?chuàng)建一個(gè)MyApplication類(lèi)繼承自系統(tǒng)的Application:
public calss MyApplication extends Application{ private static Context context; @Overrride public void onCreate(){ context=getApplicationContext(); } public static Context getContext(){ return context; } }
代碼很簡(jiǎn)單,容易理解。重寫(xiě)了父類(lèi)的onCreate()方法,并通過(guò)調(diào)用getApplicationContext()方法得到一個(gè)應(yīng)用程序級(jí)別的Context,然后又提供了一個(gè)靜態(tài)的getContext()方法,在這里將剛才獲取到的COntext進(jìn)行返回。
接下來(lái),我們需要告訴系統(tǒng),當(dāng)程序啟動(dòng)的時(shí)候應(yīng)該初始化MyApplication類(lèi),而不是系統(tǒng)默認(rèn)的Application類(lèi)。這一步需要在清單文件里面實(shí)現(xiàn),找到清單文件的<application>標(biāo)簽下進(jìn)行指定就可以了:
<manifest …… ……> <application android :name="com.example.myContext.MyApplication" //這里輸入.MyApplication也可以,或者輸入MyApplication根據(jù)AS提示自動(dòng)補(bǔ)全包名 ..> </application>
注意:這里一定要加上完整的包名,不然系統(tǒng)將無(wú)法找到這個(gè)類(lèi)。
以上就是實(shí)現(xiàn)了一種全局獲取Context的機(jī)制,在這個(gè)項(xiàng)目的任何地方使用Context,只需要調(diào)用MyApplication.getContext()就可以了。
關(guān)于自定義Application和LitePal配置沖突的問(wèn)題:
自定義需要在清單文件寫(xiě)出android.name="……"。而為了讓LitePal可以正常工作,也需要在清單文件下,配置:
android:name="org.litepal.LitePalApplication"
道理也是一樣的,這樣配置后,LitePal就能在內(nèi)部自動(dòng)獲取到Context了。
問(wèn)題:當(dāng)都已經(jīng)配置過(guò)自定義的Application怎么辦?豈不是和LitePalApplication沖突了?
解答:任何一個(gè)項(xiàng)目都只能配置一個(gè)Application. 對(duì)于這種情況,LitePalApplication給出了很簡(jiǎn)單的解決方案,在自定義的Application中去調(diào)用LitePal的初始化方法就可以了:
public calss MyApplication extends Application{ private static Context context; @Overrride public void onCreate(){ context=getApplicationContext(); LitePalApplication.initialize(context); } public static Context getContext(){ return context; } }
這種寫(xiě)法就相當(dāng)于我們把全局Context對(duì)象通過(guò)參數(shù)傳遞給了LitePal,效果和在清單文件配置LitePalApplication是一樣的。
總結(jié),如何在程序中正確的使用Context:
一般Context造成的內(nèi)存泄漏,幾乎都是當(dāng)Context銷(xiāo)毀的時(shí)候,因?yàn)楸灰脤?dǎo)致銷(xiāo)毀失敗。而Application的Context對(duì)象可以簡(jiǎn)單的理解為伴隨著進(jìn)程存在的(它的生命周期也很長(zhǎng),畢竟APP加載的時(shí)候先加載Application,我們可以自定義Application然后繼承系統(tǒng)的Application)。
正確使用:
當(dāng)Applicatin的Context能搞定的情況下,并且生命周期長(zhǎng)的對(duì)象,優(yōu)先使用Application的Context;
不要讓生命周期長(zhǎng)于Activity的對(duì)象持有Activity的引用。
盡量不要在Activity中使用非靜態(tài)內(nèi)部類(lèi)。非靜態(tài)內(nèi)部類(lèi)會(huì)隱式持有外部類(lèi)實(shí)例的引用。如果使用靜態(tài)內(nèi)部類(lèi),將外部實(shí)例引用作為弱引用持有。
獲取全局context的另一種思路:
ActivityThread是主進(jìn)程的入口,它的currentApplication返回值是application.
import android.app.Application; import java.lang.reflect.InvocationTargetException; /** * 這種方式獲取全局的Application 是一種拓展思路。 * <p> * 對(duì)于組件化項(xiàng)目,不可能把項(xiàng)目實(shí)際的Application下沉到Base,而且各個(gè)module也不需要知道Application真實(shí)名字 * <p> * 這種一次反射就能獲取全局Application對(duì)象的方式相比于在Application#OnCreate保存一份的方式顯示更加通用了 */ public class AppGlobals { private static Application sApplication; public static Application getApplication() { if (sApplication == null) { try { sApplication = (Application) Class.forName("android.app.ActivityThread") .getMethod("currentApplication") .invoke(null, (Object[]) null); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } return sApplication; } }
到此這篇關(guān)于Context的詳細(xì)介紹和實(shí)例分析的文章就介紹到這了,更多相關(guān)Context的詳細(xì)介紹內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Mybatis Plus 字段為空值時(shí)執(zhí)行更新方法未更新解決方案
這篇文章主要介紹了Mybatis Plus 字段為空值時(shí)執(zhí)行更新方法未更新解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09Java調(diào)用Python腳本傳遞數(shù)據(jù)并返回計(jì)算結(jié)果
實(shí)際工程項(xiàng)目中可能會(huì)用到Java和python兩種語(yǔ)言結(jié)合進(jìn)行,這樣就會(huì)涉及到一個(gè)問(wèn)題,Java如何調(diào)用Python腳本,感興趣的可以了解一下2021-05-05IDEA創(chuàng)建Servlet程序的兩種實(shí)現(xiàn)方法
Servlet是JavaWeb應(yīng)用程序中不可或缺的組件之一,本文主要介紹了IDEA創(chuàng)建Servlet程序的兩種實(shí)現(xiàn)方法,具有一定的參考價(jià)值,感興趣的可以了解一下2023-10-10SpringData JPA快速上手之關(guān)聯(lián)查詢及JPQL語(yǔ)句書(shū)寫(xiě)詳解
JPA都有SpringBoot的官方直接提供的starter,而Mybatis沒(méi)有,直到SpringBoot 3才開(kāi)始加入到官方模版中,這篇文章主要介紹了SpringData JPA快速上手,關(guān)聯(lián)查詢,JPQL語(yǔ)句書(shū)寫(xiě)的相關(guān)知識(shí),感興趣的朋友一起看看吧2023-09-09Java instanceof關(guān)鍵字的的進(jìn)一步理解
這篇文章主要介紹了Java instanceof關(guān)鍵字的的進(jìn)一步理解,本文用一些實(shí)例講解了instanceof操作符的一些知識(shí),需要的朋友可以參考下2015-03-03關(guān)于Spring注解@Async引發(fā)其他注解失效的解決
這篇文章主要介紹了關(guān)于Spring注解@Async引發(fā)其他注解失效的解決,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-03-03RocketMQ消息隊(duì)列實(shí)現(xiàn)隨機(jī)消息發(fā)送當(dāng)做七夕禮物
這篇文章主要為大家介紹了RocketMQ消息隊(duì)列實(shí)現(xiàn)隨機(jī)消息發(fā)送當(dāng)做七夕禮物,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08