zoukankan      html  css  js  c++  java
  • 在任意位置获取应用程序Context

    Android程序中访问资源时需要提供Context,一般来说只有在各种component中(Activity, Provider等等)才能方便的使用api来获取Context, 而在某些工具类中要获取就很麻烦了。为此,我们可以自定义一个Application类来实现这种功能。

    import android.app.Application;

    public class MyApplication extends Application {
        private static MyApplication instance;

        public static MyApplication getInstance() {
            return instance;
        }

        @Override
        public void onCreate() {
            // TODO Auto-generated method stub
            super.onCreate();
            instance = this;
        }
    }

    然后在manifest中<application>中加入name="mypackage.MyApplication"就可以在任意类中使用MyApplication.getInstance()来获取应用程序Context了。

    (二)context注意事项:

    在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. 避免非静态的内部类,尽量使用静态类,避免生命周期问题,注意内部类对外部对象引用导致的生命周期变化

    (三)获取别的包的context

    Android中有Context的概念,想必大家都知道。Context可以做很多事情,打开activity、发送广播、打开本包下文件夹和数据库、 获取classLoader、获取资源等等。如果我们得到了一个包的Context对象,那我们基本上可以做这个包自己能做的大部分事情。

             那我们能得到吗?很高兴的告诉你,能!
          Context有个createPackageContext方法,可以创建另外一个包的上下文,这个实例不同于它本身的Context实例,但是功能是一样的。


          这个方法有两个参数:
    1。packageName  包名,要得到Context的包名
    2。flags  标志位,有CONTEXT_INCLUDE_CODE和CONTEXT_IGNORE_SECURITY两个选项。 CONTEXT_INCLUDE_CODE的意思是包括代码,也就是说可以执行这个包里面的代码。CONTEXT_IGNORE_SECURITY的意思 是忽略安全警告,如果不加这个标志的话,有些功能是用不了的,会出现安全警告。


          下面给个小例子,执行另外一个包里面的某个类的方法。
          另外一个包的包名是chroya.demo,类名Main,方法名print,代码如下:

    Java代码  收藏代码
    1. package chroya.demo;  
    2.   
    3. import android.app.Activity;  
    4. import android.os.Bundle;  
    5. import android.util.Log;  
    6.   
    7. class Main extends Activity {  
    8.       
    9.     @Override  
    10.     public void onCreate(Bundle savedInstanceState) {  
    11.         super.onCreate(savedInstanceState);  
    12.     }  
    13.       
    14.     public void print(String msg) {  
    15.         Log.d("Main""msg:"+ msg);  
    16.     }  
    17. }  
    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方法的代码块如下:

    Java代码  收藏代码
    1. Context c = createPackageContext("chroya.demo", Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);  
    2. //载入这个类  
    3. Class clazz = c.getClassLoader().loadClass("chroya.demo.Main");  
    4. //新建一个实例  
    5. Object owner = clazz.newInstance();  
    6. //获取print方法,传入参数并执行  
    7. Object obj = clazz.getMethod("print", String.class).invoke(owner, "Hello");  
    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。

          怎么样,这只是一个调用其他包的代码的例子,我们获取到Context,还可以做很多事情,当然,题目所说的坏事,还是不要做为好。

  • 相关阅读:
    退役 AFO
    object_id()函数
    DataRow数组根据指定列排序
    窗口函数详解
    窗口函数详细用法
    聚合函数count里面加条件
    C#全局钩子和局部钩子记录
    SqlServer日期时间函数
    SQL中字符串截取、连接、替换等函数的用法
    C# 字符串多行显示、文本换行
  • 原文地址:https://www.cnblogs.com/Greenwood/p/2003803.html
Copyright © 2011-2022 走看看