Android开发之——Context你必须知道的一些事

作为开发者,对于Context的使用一定不陌生;你在加载资源、启动一个新的Activity、获取系统服务、获取内部文件(夹)路径、创建View操作时等都需要Context的参与,可见Context的常见性;

什么是Context上下文

  • Context
    字面意思上下文,或者叫做场景,也就是用户与操作系统操作的一个过程,比如你打电话,场景包括电话程序对应的界面,以及隐藏在背后的数据

  • 源码中的Context
    源码

    一个应用程序有几个Context

    Context数量=Activity数量+Service数量+1(Application)

Context能干什么

弹出Toast、启动Activity、启动Service、发送广播、操作数据库等等

Context作用域

作用域

如何获取Context

  • View.getContext,返回当前View对象的Context对象,通常是当前正在展示的Activity对象
  • Activity.getApplicationContext,获取当前Activity所在的(应用)进程的Context对象,通常我们使用Context对象时,要优先考虑这个全局的进程Context
  • ContextWrapper.getBaseContext():用来获取一个ContextWrapper进行装饰之前的Context,可以使用这个方法,这个方法在实际开发中使用并不多,也不建议使用
  • Activity.this 返回当前的Activity实例,如果是UI控件需要使用Activity作为Context对象,但是默认的Toast实际上使用ApplicationContext也可以

Context引起的内存泄露

  • 错误的单例模式

      public class Singleton {  
      private static Singleton instance;  
      private Context mContext;
      private Singleton(Context context) {  
      this.mContext = context;
      }
      public static Singleton getInstance(Context context)
       {
       if (instance == null) 
        {
         instance = new Singleton(context);
           }
        return instance;
       }
      }
    

    这是一个非线程安全的单例模式,instance作为静态对象,其生命周期要长于普通的对象,其中也包含Activity,假如Activity A去getInstance获得instance对象,传入this,常驻内存的Singleton保存了你传入的Activity A对象,并一直持有,即使Activity被销毁掉,但因为它的引用还存在于一个Singleton中,就不可能被GC掉,这样就导致了内存泄漏

  • View持有Activity引用

      public class MainActivity extends Activity {
         private static Drawable mDrawable;
      @Override
         protected void onCreate(Bundle saveInstanceState) {
      super.onCreate(saveInstanceState);
      setContentView(R.layout.activity_main);
      ImageView iv = new ImageView(this);
      mDrawable = getResources().getDrawable(R.drawable.ic_launcher);
      iv.setImageDrawable(mDrawable);
          }
      }
    

    有一个静态的Drawable对象当ImageView设置这个Drawable时,ImageView保存了mDrawable的引用,而ImageView传入的this是MainActivity的mContext,因为被static修饰的mDrawable是常驻内存的,MainActivity是它的间接引用,MainActivity被销毁时,也不能被GC掉,所以造成内存泄漏。

正确使用Context

  • 当Application的Context能搞定的情况下,并且生命周期长的对象,优先使用Application的Contex
  • 不要让生命周期长于Activity的对象持有到Activity的引用
  • 量不要在Activity中使用非静态内部类,因为非静态内部类会隐式持有外部类实例的引用,如果使用静态内部类,将外部实例引用作为弱引用持有

参考:
Android Context 上下文 你必须知道的一切
Context都没弄明白,还怎么做Android开发?