一惊奇、基礎知識
Context在我們開發(fā)中經常用到烙样,不管是Framework提供給我們的四大組件,還是應用級別的Application脐往,還是負責表現(xiàn)層的View相關類休吠,甚至連我們很多時候創(chuàng)建的實體類都會需要持有一個Context的引用。那么Context到底是什么呢业簿?
建議看這個:http://www.reibang.com/p/b68de4c95b05
(1)Context是什么瘤礁?
Context英文釋義是當前上下文,或者當前場景上梅尤,
官方文檔:Context
public abstractclass Context extends Object
Interface to globalinformation about an application environment. This is an abstract class whoseimplementation is provided by the Android system. It allows access toapplication-specific resources and classes, as well as up-calls forapplication-level operations such as launching activities, broadcasting andreceiving intents, etc.
由官方文檔柜思,我們可以知道:
1.該類是一個抽象(abstract class)類;
2.它描述的是一個應用程序環(huán)境的信息巷燥,即上下文赡盘;
3.通過它(Context)我們可以獲取應用程序的資源和類,也包括一些應用級別的操作(例如缰揪,啟動 Activity,廣播和服務等);
(2) Context有什么用陨享?
前面我們講過 Context 是一個抽象類,通過 Context我們可以獲取應用程序的資源和類钝腺,調用它們的方法抛姑,那么具體定義的方法有哪些呢?我們來看一下 Context 的源碼:
public abstract class Context {
public abstract void startActivity(Intent intent);
public abstract void startActivity(Intent intent, @Nullable Bundle options);
public abstract void startActivities(Intent[] intents);
public abstract void startActivities(Intent[] intents, Bundle options);
public abstract void sendBroadcast(Intent intent);
public abstract void sendBroadcast(Intent intent,
@Nullable String receiverPermission);
public abstract Intent registerReceiver(@Nullable BroadcastReceiver receiver,
IntentFilter filter);
public abstract void unregisterReceiver(BroadcastReceiver receiver);
public final String getString(@StringRes int resId) ;
public final int getColor(@ColorRes int id) ;
public final Drawable getDrawable(@DrawableRes int id);
public abstract void setTheme(@StyleRes int resid);
public abstract ApplicationInfo getApplicationInfo();
public abstract String getPackageName();
public abstract String getPackageResourcePath();
public File getSharedPrefsFile(String name) ;
public abstract SharedPreferences getSharedPreferences(String name, @PreferencesMode int mode);
......
......
}
源碼里的方法太多了艳狐,總共 4710 行定硝。我們從以上部分源碼看到了熟悉的對象---Application、Activity毫目、Service蔬啡、Broadcast、這些對象和 Context 的關系到底是什么呢蒜茴?我們看一下官方文檔可知:
總結:
1.Acitiivity 繼承自ContextThemeWrapper--->再繼承ContextWrapper--->Context星爪。
2.Appliction 、Service繼承自ContextWrapper--->再繼承Context粉私。
3.Application顽腾、Service 和 Activity 最終都是繼承自Context,所以它們是同一個上下文。
通過以上的繼承關系抄肖,我們就可以知道久信,Context的具體作用會包括:
- 啟動一個新的Activity
- 啟動和停止Service
- 發(fā)送廣播消息(Intent)
- 注冊廣播消息(Intent)接收者
- 可以訪問APK中各種資源,如Resources和AssetManager
- 創(chuàng)建View
- 訪問Package的相關信息
- APK的各種權限管理
(3)Context 創(chuàng)建時機漓摩?
由上面分析的繼承關系裙士,我們可以知道,Context創(chuàng)建的時機有三個:
①創(chuàng)建Application 對象時管毙, 而且整個App共一個Application對象腿椎;
②創(chuàng)建Service對象時;
③創(chuàng)建Activity對象時夭咬;
所以應用程序App共有的Context數目公式為:
Service個數 + Activity個數 + 1(Application對應的Context實例)
二啃炸、Context 使用時注意事項:
(1)Context 使用時注意什么?
如上卓舵,Android中context可以作很多操作南用,但是最主要的功能是加載和訪問資源。在android中常用的context有兩種掏湾,一種是application context裹虫,一種是activity context,通常我們在各種類和方法間傳遞的是activity context融击。
兩者的區(qū)別:
public class MyActivity extends Activity {
public void method() {
mContext = this; // since Activity extends Context
mContext = getApplicationContext();
}
}
this是Activity 的實例筑公,擴展了Context,其生命周期是Activity 創(chuàng)建到銷毀砚嘴。getApplicationContext()返回應用的上下文十酣,生命周期是整個應用,應用摧毀它才被摧毀际长。Activity.this的context 返回當前activity的上下文耸采,屬于activity ,activity摧毀時被摧毀工育。
使用Context時最需要注意的一個點就是虾宇,使用了不正確的context,比如有一個全局的數據操作類用到了context如绸,這個時候就要getApplicationContext 而不是用ACtivity嘱朽,如果在這個全局操作中引用的是Activity的context,那么就會一直引用Activity的資源怔接,導致GC無法回收這部分內存搪泳,從而最終導致了內存泄漏。
內存泄漏是開發(fā)中常見的錯誤之一扼脐,能不能發(fā)現(xiàn)取決于開發(fā)者的經驗岸军,當然了我們也會依賴現(xiàn)有的內存泄漏庫奋刽,但是如果我們在開發(fā)的源頭減少內存泄漏的概率,那么后期的工作會少很多艰赞。
以下是避免context相關的內存泄露佣谐,給出的幾點建議:
- 不要讓生命周期長的對象引用activity context,即保證引用activity的對象要與activity本身生命周期是一樣的方妖;
- 對于生命周期長的對象狭魂,可以使用application context;
- 避免非靜態(tài)的內部類党觅,盡量使用靜態(tài)類雌澄,避免生命周期問題,注意內部類對外部對象引用導致的生命周期變化仔役;
(2)Context的常見應用場景
以下的表列舉的是三種Context對象的對應使用場景:
從表中可以看到掷伙,和UI相關的都使用Activity的Context對象。
小結:如上分析又兵,Context在對應開發(fā)里的來源就是三個——Activity、Service和Appliaction卒废,那么我們該如何選擇使用哪一個Context對象呢沛厨?一個比較簡單的方法是,當你無法確定使用某個Context對象是否會造成長引用導致內存泄漏時摔认,那么就使用Appliaction的Context對象逆皮,因為Appliaction存在于整個應用的生命周期內。
三参袱、實際開發(fā)中用到自定義 Application
在實際開發(fā)中电谣,我們往往會為項目定義一個Applictaion,然后在AndroidMainfest.xml文件中進行注冊抹蚀,
<application
android:name=".MyApplication"
android:label="@string/app_name"
android:theme="@style/AppThemeLight">
...
</application>
而且在自定義Application往往會定義好一個靜態(tài)方法剿牺,用以全局獲取application實例:
public class MyApplication extends Application {
private static MyApplication myApplication ;
public static MyApplication getInstance() {
return myApplication ;
}
@Override
public void onCreate() {
super.onCreate();
myApplication = this;
}
}
Activity和Application都是Context的子類,但是他們維護的生命周期不一樣环壤。前者維護一個Acitivity的生命周期晒来,所以其對應的Context也只能訪問該activity內的各種資源。后者則是維護一個Application的生命周期郑现。
附錄:其他一些方法和使用context的注意事項
1.如何判斷context是屬于哪個activity湃崩?
context.getClass().getSimpleName()
2.全局不同如何獲取對應的context?
View.getContext()接箫,返回當前View對象的Context對象攒读,通常是當前正在展示的Activity對象,這個是View類中提供的方法辛友,在繼承了View的類中才可以調用薄扁,返回的是當前View運行在哪個Activity Context中;
Activity.getApplicationContext(),獲取當前Activity所在的(應用)進程的Context對象泌辫,通常我們使用Context對象時随夸,要優(yōu)先考慮這個全局的進程Context;
ContextWrapper.getBaseContext():用來獲取一個ContextWrapper進行裝飾之前的Context震放,可以使用這個方法宾毒,這個方法在實際開發(fā)中使用并不多,也不建議使用殿遂;
Activity.this 诈铛,表示Activity對象,一般用在內部類中指示外面的this墨礁,如果在內部類直接用this幢竹,指示的是內部類本身;
this恩静,表示當前對象焕毫;一般而言,在哪個類中調用驶乾,就是指向該對象邑飒;
getActivity(),Fragment中级乐,返回Fragment綁定的Activity;
靜態(tài)加載一個Fragment疙咸,在onCreateView()方法中通過getActivity獲取上下文實例:
public class CollageFragment extends Fragment {
private CameraPreviewActivity activity;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
root_view = inflater.inflate(R.layout.fragment_collage, container, false);
activity = (CameraPreviewActivity) getActivity();
init();
return root_view;
}
private void init() {
// 利用此activity發(fā)送廣播
activity.sendBroadcast(new Intent(CameraPreviewActivity.REMOVE_SCENES_EFFECT_WHEN_NOT_FULL_MODE));
MobClickUtil.onEvent(activity,"main_click_11");
// 調用此activity的實例方法
activity.setRatio("1x1",0);
}
}
3.四大組件可以像普通Java類一樣,采用new的方式實例化嗎风科?
Android程序不像Java程序一樣撒轮,隨便創(chuàng)建一個類,寫個main()方法就能運行贼穆,Android應用模型是基于組件的應用設計模式题山,組件的運行要有一個完整的Android工程環(huán)境,在這個環(huán)境下扮惦,Activity臀蛛、Service等系統(tǒng)組件才能夠正常工作,而這些組件并不能采用普通的Java對象創(chuàng)建方式崖蜜,new一下就能創(chuàng)建實例了浊仆,而是要有它們各自的上下文環(huán)境,也就是我們這里討論的Context豫领÷帐粒可以這樣講,Context是維持Android程序中各組件能夠正常工作的一個核心功能類等恐。
參考 作者:Chin_style
原文:https://blog.csdn.net/weixin_41101173/article/details/7988284