1.在任意位置獲取應用程序Context
java
Android程序中訪問資源時須要提供Context,通常來講只有在各類component中(Activity, Provider等等)才能方便的使用api來獲取Context;喜歡編程的人都知道,編寫工具類能夠有效的實現代碼複用,而在Android下某些工具類的編寫很讓人困惑,例如:咱們要在工具類中獲取SharedPreferences,那就須要Context的支持。android
爲了解決這寫由Context帶來的麻煩,咱們能夠自定義一個Application類來實現這種功能。
import android.app.Application;
public class ContextUtil extends Application {
private static ContextUtil instance;
public static ContextUtil getInstance() {
return instance;
}
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
instance = this;
}
}數據庫
而後在manifest中<application>中加入Android:name="mypackage.ContextUtil",這樣咱們就能夠在任何一個類下面獲取Context,例如:Context c=ContextUtil.getInstance();編程
2.context注意事項:api
在android中context能夠做不少操做,可是最主要的功能是加載和訪問資源。在android中有兩種context,一種是 application context,一種是activity context,一般咱們在各類類和方法間傳遞的是activity context。
好比一個activity的onCreate:
protected void onCreate(Bundle state) {
super.onCreate(state);
TextView label = new TextView(this); //傳遞context給view control
label.setText("Leaks are bad");
setContentView(label);
}
把activity context傳遞給view,意味着view擁有一個指向activity的引用,進而引用activity佔有的資源:view hierachy, resource等。
這樣若是context發生內存泄露的話,就會泄露不少內存。
這裏泄露的意思是gc沒有辦法回收activity的內存。
Leaking an entire activity是很容易的一件事。
當屏幕旋轉的時候,系統會銷燬當前的activity,保存狀態信息,再建立一個新的。
好比咱們寫了一個應用程序,它須要加載一個很大的圖片,咱們不但願每次旋轉屏 幕的時候都銷燬這個圖片,從新加載。實現這個要求的簡單想法就是定義一個靜態的Drawable,這樣Activity 類建立銷燬它始終保存在內存中。
實現相似:
public class myactivity extends Activity {
private static Drawable sBackground;
protected void onCreate(Bundle state) {
super.onCreate(state);
TextView label = new TextView(this);
label.setText("Leaks are bad");
if (sBackground == null) {
sBackground = getDrawable(R.drawable.large_bitmap);
}
label.setBackgroundDrawable(sBackground);//drawable attached to a view
setContentView(label);
}
}
這段程序看起來很簡單,可是卻問題很大。當屏幕旋轉的時候會有leak(即gc無法銷燬activity)。
咱們剛纔說過,屏幕旋轉的時候系統會銷燬當前的activity。可是當drawable和view關聯後,drawable保存了view的 reference,即sBackground保存了label的引用,而label保存了activity的引用。既然drawable不能銷燬,它所 引用和間接引用的都不能銷燬,這樣系統就沒有辦法銷燬當前的activity,因而形成了內存泄露。gc對這種類型的內存泄露是無能爲力的。
避免這種內存泄露的方法是避免activity中的任何對象的生命週期長過activity,避免因爲對象對 activity的引用致使activity不能正常被銷燬。咱們可使用application context。application context伴隨application的一輩子,與activity的生命週期無關。application context能夠經過Context.getApplicationContext或者Activity.getApplication方法獲取。
避免context相關的內存泄露,記住如下幾點:
1. 不要讓生命週期長的對象引用activity context,即保證引用activity的對象要與activity自己生命週期是同樣的
2. 對於生命週期長的對象,可使用application context
3. 避免非靜態的內部類,儘可能使用靜態類,避免生命週期問題,注意內部類對外部對象引用致使的生命週期變化安全
3.獲取別的包的Contextapp
Android中有Context的概念,想必你們都知道。Context能夠作不少事情,打開activity、發送廣播、打開本包下文件夾和數據庫、獲取classLoader、獲取資源等等。若是咱們獲得了一個包的Context對象,那咱們基本上能夠作這個包本身能作的大部分事情。ide
Context有個createPackageContext方法,能夠建立另一個包的上下文,這個實例不一樣於它自己的Context實例,可是功能是同樣的。工具
這個方法有兩個參數:
1。packageName 包名,要獲得Context的包名
2。flags 標誌位,有CONTEXT_INCLUDE_CODE和CONTEXT_IGNORE_SECURITY兩個選項。 CONTEXT_INCLUDE_CODE的意思是包括代碼,也就是說能夠執行這個包裏面的代碼。CONTEXT_IGNORE_SECURITY的意思是忽略安全警告,若是不加這個標誌的話,有些功能是用不了的,會出現安全警告。this
下面給個小例子,執行另一個包裏面的某個類的方法。
另一個包的包名是chroya.demo,類名Main,方法名print,代碼以下:
package chroya.demo; import android.app.Activity; import android.os.Bundle; import android.util.Log; class Main extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } public void print(String msg) { Log.d("Main", "msg:"+ msg); } }
本包的調用Main的print方法的代碼塊以下:
Context c = createPackageContext("chroya.demo", Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY); //載入這個類 Class clazz = c.getClassLoader().loadClass("chroya.demo.Main"); //新建一個實例 Object owner = clazz.newInstance(); //獲取print方法,傳入參數並執行 Object obj = clazz.getMethod("print", String.class).invoke(owner, "Hello");
ok,這樣,咱們就調用了chroya.demo包的Main類的print方法,執行結果,打印出了Hello。