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。