黑马程序员技术交流社区

标题: [深圳特色][问答网]Context的作用是什么? [打印本页]

作者: 袁老师    时间: 2016-3-13 21:19
标题: [深圳特色][问答网]Context的作用是什么?
本帖最后由 袁也老师 于 2016-3-13 21:21 编辑

Context的作用是什么?下面深圳问答网的师生来探讨一下这个问题.



Context,我们在android开发中经常见到这个名词,尤其是某些方法的参数列表,像是我们Toast中的makeText()中的第一个参数,就是Context。可以这么说,Context是 android中的基础,只有切实掌握好Context的概念和用法,我们才能写出更好的代码。那么,现在就让我们一起来看一下所谓的Context。
      Context,如果是直接从文档翻译过来,就真的是十足的专业了:提供应用环境全局信息的接口,并且这个接口是由抽象类实现的,它的执行被android系统所提供,允许我们获取以应用为特征的资源和类型,同时启动应用级的操作,如启动Activity,broadcasting和接收intent。
       从这段话就可以发现,Context就是一个作为接口使用的抽象类,而且这个接口提供的是应用的全局信息,因为是android系统所提供的,所以我们大多时候都是可以直接得到的,这点会在下面讲到。我们来看看它的用处,允许我们获取以应用为特征的资源和类型,同时启动应用级的操作。什么意思?通俗来讲,就是我们可以获取其他应用的资源和类,至于下半句的启动应用级的操作,我们可以暂时忽略,因为不是这里的重点。
一.Context的作用
      Context的最大作用就是我们可以通过传递它来获得其他Activity或Application的相关资源和方法,它就相当于它们的引用,我们通过引用来获得对象的封装,这也是我们面向对象的基础,所以,我们主要利用它来加载和访问资源。
二 .Context的类型
     Context的类型有两种,一种是Activity-Context,另一种是Application-Activity,这两种的区别就在于它们的生命周期不一样,一个是随着Activity的销毁而销毁,另一个是伴随整个Application,鉴于我们以前学习java,C++这些语言的经验,都会意识到,这些生命周期的不同可能会导致不同行为以及一些错误,这些都会在接下来讲到,因为它们是我们使用Context必须注意的。
1.Application-Context
   这个之所以先讲,是因为这个比较麻烦,在于它的获取需要通过一些手段。
   Application-Context的生命周期是整个应用,所以,对于它的使用必须慎重,大部分情况下都要避免使用它,因为它会导致内存泄露的问题。我们先来举个例子,如果我们现在在一个Activity中引入一个Application-Context,那么,当我们这个Activity关闭的时候,这个Application-Context是不会消失的,因为它的生命周期要比我们的Activity长,如果只是一些用来计算的数据还好,但是如果这个Context与我们的Activity的创建有关,或者与我们在Activity要销毁的资源比如图片资源有关,那么,问题就大条了!因为我们的Activity或图片就不能正常销毁,因为它与Application-Context相关联,如果不能正常的释放掉与它们相关的内存,就会出现所谓的内存泄露的问题。这种问题有时候是非常隐晦的,以至于我们根本无法察觉到,所以我们必须遵守相关的使用原则。
      现在我们以一个例子来示例如何获得Application-Context。
      要想获得Application-Context,我们可以先声明一个Application的子类。
  1. class A extends Application{}
复制代码
现在,我们在这个类中添加一些东西来证明可以通过Context来获得A的相关资源和方法。这次我们使用一个Toast。
      首先,是在我们的类A里添加以下的内容:
  1. String s = "hello";
  2.       public String getString(String str){
  3.              s = str;
  4.              return s;
  5.       }
复制代码
然后再在我们的Activity B中尝试取用A的数据和方法:   
  1. A a = (A)getApplicationContext();
  2.        String s = a.s;
  3.        s = a.getString("hello word");
  4.        Toast.makeText(this, s, Toast.LENGTH_LONG).show();
复制代码

然后我们还必须注意在我们的mainfest文件中注册我们的application:
  1. <application android:name=".A"></application>
复制代码
注意,我们的mainfes始的at文件中一开pplication是没有名字的,因为我们一般都只是启动一个Activity,而不是一个application,所以,可以将我们这个application的名字注册为继承自Application的子类A,这样才能正常显示出一个Toast出来。如果没有这么做,就可能报出这样的错误:android.app.Application cannot be cast to A。
      在上面的例子中可以看到,通过一个Application的子类就能在我们的Activity中调用它的资源和方法,但是其实完全可以不用这样做,声明一个class,然后new一个实例同样可以做到这点,但是这里只是想要大家明白,Context的确可以传递相关类的引用,并且通过这个引用来获取相关类的资源和方法,而且这个Context甚至可以转化为具体的子类,我们的getApplicationContext()返回的其实是一个Context,之所以能将它转换为A,是因为Context传递的就是Application-Context,它是一个Application类型的,而类A是Application的子类,父类转化为子类,这里就会有个疑问,就是我们的父类是不可以强制转化为子类的,因为子类可能有父类没有的方法,这样的转化就会出现问题,但是,我们也知道,可以将子类的引用转化为父类,因为父类的引用是可以指向子类的,所以这里是想说明我们的Context真的是一个引用。
      Application-Context的生命周期为整个Application,所以如果是一些需要在整个应用期间都存在的资源,我们可以将它放进一个Application-Context中,然后通过获取这个Context来使用它们。
2.Activity-Context
      正如上面讲的一样,这个Context的生命周期是和得到它的引用的Activity一样长,如果这个Activity结束了,那么,这个Context也会得到释放。它并不像我们上面的Application-Context需要特意去获得,可以在一个Activity中使用this就可以获得当前Activity的Context。还是拿上面例子中的Toast.makeText(this, s, Toast.LENGTH_LONG).show(),其中的this就是当前的Activity-Context,但是,一味的使用this是很危险的,我们要注意的就是,在匿名内部类如果单纯只是使用this是会出错的,因为内部类中使用this得到的是内部类的对象引用,而不是我们要得到的外部类的引用,于是,这时候就必须使用类名.this这种方式,这种做法在按钮的事件监听中是特别要注意的。
3.使用规则
     因为使用Application-Cntext会出现内存泄露的危险,所以我们一般都是使用Activity-Context。下面就是这两者的使用规则:
    (1)不要让生命周期长的对象引用Activity-Context,保证引用要与Ativity本身生命周期是一样的,对于生命周期长的对象,使用Application-Context 。
     如果你想要在某个Activity的界面上显示某个组件,比如说Toast,那么,请把你的Activity的Context作为参数传给Toast,这样就能将你的Activity和Toast关联起来,但是,如果你想要在一个Activity中设置好你的Toast,然后再在另一个Activity中显示,记住,你可以有两种选择,一种,就是通过我们的Intent:
  1. Intent intent = new Intent(Activity1.this, Activity2.class);
  2.       startActivity(intent);
复制代码
  这个Activity1就是我们要显示Toast的Activity,而Acticity2就是我们设置Toast的Activity。

      但是,如果想要在Activity1中调用Toast.show(),接受Activity2中返回的Toast的话,那么,使用默认的样式是非常简单的,如果你真的想要使用自定义的格式,自定义一个布局文件Toast.xml,那么,请在你的Activity1中写下这几句:
  1. LayoutInflater layout = getLayoutInflater();
  2.       View view = layout.inflate(R.layout.toast, null);  
复制代码

记住,必须是在setContentView()之后进行切换,不然就会报错,而且,必须是在你要显示的Activity的setContentView(),如果你放在Activity2中的setContentView()也是会出错,就是空指针,因为我们的layout的元素只有在setContentView()之后才开始分配内存,而且我们只是调用Activity2的方法而已,并没有启动Activity2,这点必须注意。














作者: 步行走向前    时间: 2016-3-14 18:35
额。。。我一个菜鸟
作者: jiaoshaowei    时间: 2016-3-18 21:10
获得其他Activity或Application的相关资源和方法
作者: hjh987099654    时间: 2016-3-20 14:16
又学到了
作者: 452296824    时间: 2016-3-21 22:56
当我们访问当前应用的资源,启动一个新的activity的时候都需要提供Context。
Context是一个抽象基类,我们通过它访问当前包的资源(getResources、getAssets)和启动其他组件(Activity、Service、Broadcast)以及得到各种服务(getSystemService),当然,通过Context能得到的不仅仅只有上述这些内容。对Context的理解可以来说:Context提供了一个应用的运行环境,在Context的大环境里,应用才可以访问资源,才能完成和其他组件、服务的交互,Context定义了一套基本的功能接口,可以理解为一套规范,而Activity和Service是实现这套规范的子类,这么说也许并不准确,因为这套规范实际是被ContextImpl类统一实现的,Activity和Service只是继承并有选择性地重写了某些规范的实现。




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2