Android 上下文Context(最权威的官方教程)








可以看到Activity、Service、Application都是Context的子类;

也就是说,Android系统的角度来理解:Context是一个场景,代表与操作系统的交互的一种过程。从程序的角度上来理解:Context是个抽象类,而Activity、Service、Application等都是该类的一个实现。

在仔细看一下上图:Activity、Service、Application都是继承自ContextWrapper,而ContextWrapper内部会包含一个base context,由这个base context去实现了绝大多数的方法。




Context的应用场景,正确使用Context


一般Context造成的内存泄漏,几乎都是当Context销毁的时候,却因为被引用导致销毁失败,而Application的Context对象可以理解为随着进程存在的,所以我们总结出使用Context的正确姿势:

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

Context内存泄漏

  1. public static synchronized CustomManager getInstance(Context context)  
  2.     {  
  3.         if (sInstance == null)  
  4.         {  
  5.             sInstance = new CustomManager(context.getApplicationContext());  
  6.         }  
  7.         return sInstance;  
  8.     }  



二、 什么时候创建Context实例 

 

      熟悉了Context的继承关系后,我们接下来分析应用程序在什么情况需要创建Context对象的?应用程序创建Context实例的

 情况有如下几种情况:

      1、创建Application 对象时, 而且整个App共一个Application对象

      2、创建Service对象时

      3、创建Activity对象时

 

    因此应用程序App共有的Context数目公式为:

 

                     总Context实例个数 = Service个数 + Activity个数 + 1(Application对应的Context实例)

                     单进程的情况:Context数量=Activity数量+Service数量+1 (Application=1)


Broadcast Receiver,Content Provider并不是Context的子类,他们所持有的Context都是其他地方传过去的,所以并不计入Context总数。

很显然Activity,Service,Application都是其子类,其地位和作用不言而喻。


      1、创建Application对象的时机

Application里面的一个onBaseContextAttached方法
  1.  @Override
        public void onBaseContextAttached(Context base) {
            super.onBaseContextAttached(base);
            String  pkgName = getApplication().getPackageName();
            CXLog.d(TAG,"pkgName:"+pkgName);
    //        mPluginApp.attachBaseContext(getApplication(),pkgName);
            mPluginApp.attachBaseContext(base, BuildConfig.APPLICATION_ID);
        }

  1. //创建Application时同时创建的ContextIml实例  
  2. private final void handleBindApplication(AppBindData data){  
  3.     ...  
  4.     ///创建Application对象  
  5.     Application app = data.info.makeApplication(data.restrictedBackupMode, null);  
  6.     ...  
  7. }  
  8.   
  9. public Application makeApplication(boolean forceDefaultAppClass, Instrumentation instrumentation) {  
  10.     ...  
  11.     try {  
  12.         java.lang.ClassLoader cl = getClassLoader();  
  13.         ContextImpl appContext = new ContextImpl();    //创建一个ContextImpl对象实例  
  14.         appContext.init(thisnull, mActivityThread);  //初始化该ContextIml实例的相关属性  
  15.         ///新建一个Application对象   
  16.         app = mActivityThread.mInstrumentation.newApplication(  
  17.                 cl, appClass, appContext);  
  18.        appContext.setOuterContext(app);  //将该Application实例传递给该ContextImpl实例           
  19.     }   
  20.     ...  
  21. }  


        2、创建Activity对象的时机

    1. //创建一个Activity实例时同时创建ContextIml实例  
    2. private final void handleLaunchActivity(ActivityRecord r, Intent customIntent) {  
    3.     ...  
    4.     Activity a = performLaunchActivity(r, customIntent);  //启动一个Activity  
    5. }  
    6. private final Activity performLaunchActivity(ActivityRecord r, Intent customIntent) {  
    7.     ...  
    8.     Activity activity = null;  
    9.     try {  
    10.         //创建一个Activity对象实例  
    11.         java.lang.ClassLoader cl = r.packageInfo.getClassLoader();  
    12.         activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);  
    13.     }  
    14.     if (activity != null) {  
    15.         ContextImpl appContext = new ContextImpl();      //创建一个Activity实例  
    16.         appContext.init(r.packageInfo, r.token, this);   //初始化该ContextIml实例的相关属性  
    17.         appContext.setOuterContext(activity);            //将该Activity信息传递给该ContextImpl实例  
    18.         ...  
    1.     }  
    2.     ...      
    3. }  
 

   3、创建Service对象的时机


  1. //创建一个Service实例时同时创建ContextIml实例  
  2. private final void handleCreateService(CreateServiceData data){  
  3.     ...  
  4.     //创建一个Service实例  
  5.     Service service = null;  
  6.     try {  
  7.         java.lang.ClassLoader cl = packageInfo.getClassLoader();  
  8.         service = (Service) cl.loadClass(data.info.name).newInstance();  
  9.     } catch (Exception e) {  
  10.     }  
  11.     ...  
  12.     ContextImpl context = new ContextImpl(); //创建一个ContextImpl对象实例  
  13.     context.init(packageInfo, nullthis);   //初始化该ContextIml实例的相关属性  
  14.     //获得我们之前创建的Application对象信息  
  15.     Application app = packageInfo.makeApplication(false, mInstrumentation);  
  16.     //将该Service信息传递给该ContextImpl实例  
  17.     context.setOuterContext(service);  
  18.     ...  
  19. }  

总结:都用到了 ContextImpl context =  new  ContextImpl();  //创建一个ContextImpl对象实例   












可以看到Activity、Service、Application都是Context的子类;

也就是说,Android系统的角度来理解:Context是一个场景,代表与操作系统的交互的一种过程。从程序的角度上来理解:Context是个抽象类,而Activity、Service、Application等都是该类的一个实现。

在仔细看一下上图:Activity、Service、Application都是继承自ContextWrapper,而ContextWrapper内部会包含一个base context,由这个base context去实现了绝大多数的方法。




Context的应用场景,正确使用Context


一般Context造成的内存泄漏,几乎都是当Context销毁的时候,却因为被引用导致销毁失败,而Application的Context对象可以理解为随着进程存在的,所以我们总结出使用Context的正确姿势:

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

Context内存泄漏

  1. public static synchronized CustomManager getInstance(Context context)  
  2.     {  
  3.         if (sInstance == null)  
  4.         {  
  5.             sInstance = new CustomManager(context.getApplicationContext());  
  6.         }  
  7.         return sInstance;  
  8.     }  




二、 什么时候创建Context实例 

 

      熟悉了Context的继承关系后,我们接下来分析应用程序在什么情况需要创建Context对象的?应用程序创建Context实例的

 情况有如下几种情况:

      1、创建Application 对象时, 而且整个App共一个Application对象

      2、创建Service对象时

      3、创建Activity对象时

 

    因此应用程序App共有的Context数目公式为:

 

                     总Context实例个数 = Service个数 + Activity个数 + 1(Application对应的Context实例)

                     单进程的情况:Context数量=Activity数量+Service数量+1 (Application=1)


Broadcast Receiver,Content Provider并不是Context的子类,他们所持有的Context都是其他地方传过去的,所以并不计入Context总数。

很显然Activity,Service,Application都是其子类,其地位和作用不言而喻。


      1、创建Application对象的时机

Application里面的一个onBaseContextAttached方法
  1.  @Override
        public void onBaseContextAttached(Context base) {
            super.onBaseContextAttached(base);
            String  pkgName = getApplication().getPackageName();
            CXLog.d(TAG,"pkgName:"+pkgName);
    //        mPluginApp.attachBaseContext(getApplication(),pkgName);
            mPluginApp.attachBaseContext(base, BuildConfig.APPLICATION_ID);
        }

  1. //创建Application时同时创建的ContextIml实例  
  2. private final void handleBindApplication(AppBindData data){  
  3.     ...  
  4.     ///创建Application对象  
  5.     Application app = data.info.makeApplication(data.restrictedBackupMode, null);  
  6.     ...  
  7. }  
  8.   
  9. public Application makeApplication(boolean forceDefaultAppClass, Instrumentation instrumentation) {  
  10.     ...  
  11.     try {  
  12.         java.lang.ClassLoader cl = getClassLoader();  
  13.         ContextImpl appContext = new ContextImpl();    //创建一个ContextImpl对象实例  
  14.         appContext.init(thisnull, mActivityThread);  //初始化该ContextIml实例的相关属性  
  15.         ///新建一个Application对象   
  16.         app = mActivityThread.mInstrumentation.newApplication(  
  17.                 cl, appClass, appContext);  
  18.        appContext.setOuterContext(app);  //将该Application实例传递给该ContextImpl实例           
  19.     }   
  20.     ...  
  21. }  


        2、创建Activity对象的时机

    1. //创建一个Activity实例时同时创建ContextIml实例  
    2. private final void handleLaunchActivity(ActivityRecord r, Intent customIntent) {  
    3.     ...  
    4.     Activity a = performLaunchActivity(r, customIntent);  //启动一个Activity  
    5. }  
    6. private final Activity performLaunchActivity(ActivityRecord r, Intent customIntent) {  
    7.     ...  
    8.     Activity activity = null;  
    9.     try {  
    10.         //创建一个Activity对象实例  
    11.         java.lang.ClassLoader cl = r.packageInfo.getClassLoader();  
    12.         activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);  
    13.     }  
    14.     if (activity != null) {  
    15.         ContextImpl appContext = new ContextImpl();      //创建一个Activity实例  
    16.         appContext.init(r.packageInfo, r.token, this);   //初始化该ContextIml实例的相关属性  
    17.         appContext.setOuterContext(activity);            //将该Activity信息传递给该ContextImpl实例  
    18.         ...  
    1.     }  
    2.     ...      
    3. }  
 

   3、创建Service对象的时机


  1. //创建一个Service实例时同时创建ContextIml实例  
  2. private final void handleCreateService(CreateServiceData data){  
  3.     ...  
  4.     //创建一个Service实例  
  5.     Service service = null;  
  6.     try {  
  7.         java.lang.ClassLoader cl = packageInfo.getClassLoader();  
  8.         service = (Service) cl.loadClass(data.info.name).newInstance();  
  9.     } catch (Exception e) {  
  10.     }  
  11.     ...  
  12.     ContextImpl context = new ContextImpl(); //创建一个ContextImpl对象实例  
  13.     context.init(packageInfo, nullthis);   //初始化该ContextIml实例的相关属性  
  14.     //获得我们之前创建的Application对象信息  
  15.     Application app = packageInfo.makeApplication(false, mInstrumentation);  
  16.     //将该Service信息传递给该ContextImpl实例  
  17.     context.setOuterContext(service);  
  18.     ...  
  19. }  

总结:都用到了 ContextImpl context =  new  ContextImpl();  //创建一个ContextImpl对象实例   



问题:
Context的实例是什么时候创建的?一个应用里面会有几个Context的实例?

问题:
Context的实例是什么时候创建的?一个应用里面会有几个Context的实例?
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值