Android 基础—— 对Context的理解与使用技巧

一、Context 基础概念      

1、什么是Context      

    1) Context是一个抽象类,其通用实现在ContextImpl类中。

    2) Context:是一个访问application环境全局信息的接口,通过它可以访问application的资源和相关的类,其主要功能如下:

        • 启动Activity
        • 启动和停止Service
        • 发送广播消息(Intent)
        • 注册广播消息(Intent)接收者
        • 可以访问APK中各种资源(如Resources和AssetManager等)
        • 可以访问Package的相关信息
        • APK的各种权限管理

        从以上分析可以看出,Context就是一个对APK包无所不知的大管家,大家需要什么,直接问它就可以了。

   3) Context 与View 的关系
        View与Context(或Activity)的关系类似于明星与经纪人的关系,所以创建View时,必须明确指定其Context(即经纪人或大管家),否则View就成不了明星。

         

       另外有一个简单的问题是,一个应用程序App中存在多少个Context实例对象呢?

       Context,中文直译为“上下文”,SDK中对其说明如下:

       Interface to global information about an application environment. This is an abstract class whose implementationis provided by the Android system. It allows access to application-specific resources and classes, as well as up-callsfor application-level operations such as launching activities, broadcasting and receiving intents, etc

 

从上可知一下三点,即:

1、它描述的是一个应用程序环境的信息,即上下文

2、该类是一个抽象(abstract class)类,Android提供了该抽象类的具体实现类(后面我们会讲到是ContextIml类)。

3、通过它我们可以获取应用程序的资源和类,也包括一些应用级别操作,例如:启动一个Activity,发送广播,接受Intent信息等。

 

应用程序创建Context实例的情况有如下几种情况:

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

2、创建Service对象时

3、创建Activity对象时

因此应用程序App共有的Context数目公式为:总Context实例个数 = Service个数 + Activity个数 + 1(Application对应的Context实例)

 

2、 Context 类结构

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

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

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

 

 

二、具体创建Context的时机

 1、创建Application对象的时机

       每个应用程序在第一次启动时,都会首先创建Application对象。如果对应用程序启动一个Activity(startActivity)流程比较清楚的话,创建Application的时机在创建handleBindApplication()方法中。

 

2、创建Activity对象的时机

      通过startActivity() 或startActivityForResult() 请求启动一个Activity时,如果系统检测需要新建一个Activity对象时,就会回调handleLaunchActivity()方法,该方法继而调用performLaunchActivity()方法,去创建一个Activity实例,并且回调onCreate(),onStart()方法等。

 

3、创建Service对象的时机

     通过startService或者bindService时,如果系统检测到需要新创建一个Service实例,就会回调handleCreateService()方法,完成相关数据操作。

 

三、Context 的具体使用     

         Android中context可以作很多操作,但是最主要的功能是加载和访问资源。在android中常用两种context,一种是application context,一种是activity context,通常我们在各种类和方法间传递的是activity context。

继承关系:

 

区别联系:

[java] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. public class MyActivity extends Activity {  
  2.     public void method() {  
  3.         mContext = this// since Activity extends Context  
  4.         mContext = getApplicationContext();  
  5.         mContext = getBaseContext();  
  6.     }  
  7. }  

      this 是Activity 的实例,扩展了Context,其生命周期是Activity 创建到销毁。getApplicationContext()返回应用的上下文,生命周期是整个应用,应用摧毁它才摧毁。Activity.this的context 返回当前activity的上下文,属于activity ,activity摧毁他就摧毁getBaseContext() 返回由构造函数指定或setBaseContext()设置的上下文,SDK文档很少,不推荐使用搞清楚了生命周期就会在使用过程中犯错误,比如有一个全局的数据操作类用到了context,这个时候就要getApplicationContext 而不是用ACtivity,这就保证了数据库的操作与activity无关(不会一直引用Activity的资源,防止内存泄漏)。

 

应用场景:

比如一个activity的onCreate:

[java] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. protected void onCreate(Bundle state) {  
  2.     super.onCreate(state);  
  3.     TextView label = new TextView(this);   
  4.     label.setText("Leaks are bad");  
  5.     setContentView(label);  
  6. }  

把activity context传递给view,意味着view拥有一个指向activity的引用,进而引用activity占有的资源:view hierachy, resource等。这样如果context发生内存泄露的话,就会泄露很多内存。这里泄露的意思是gc没有办法回收activity的内存。

 

Leaking an entire activity是很容易的一件事。当屏幕旋转的时候,系统会销毁当前的activity,保存状态信息,再创建一个新的activity。

比如我们写了一个应用程序,它需要加载一个很大的图片,我们不希望每次旋转屏幕的时候都销毁这个图片重新加载。

实现这个要求的简单想法就是定义一个静态的Drawable,这样Activity类创建销毁它始终保存在内存中。实现示例:

[java] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. public class myactivity extends Activity {  
  2.     private static Drawable sBackground;  
  3.     protected void onCreate(Bundle state) {  
  4.         super.onCreate(state);  
  5.         TextView label = new TextView(this);  
  6.         label.setText("Leaks are bad");  
  7.         if (sBackground == null) {  
  8.             sBackground = getDrawable(R.drawable.large_bitmap);  
  9.         }  
  10.         label.setBackgroundDrawable(sBackground);//drawable attached to a view  
  11.         setContentView(label);  
  12. }  

       这段程序看起来很简单,但是却问题很大。当屏幕旋转的时候会有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.getApplicationContext()方法获取。

      定制一个自己的Application:首先创建一个MyApplication类继承自Application

[java] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. public class MyApplication extends Application{  
  2.     private static Context context;  
  3.   
  4.     public void onCreate(){  
  5.         context=getApplicationContext();  
  6.     }  
  7.   
  8.     public static Context getContext(){  
  9.         return context;  
  10.     }  
  11. }  
  12. <p> </p>  

注意:当程序启动的时候应该初始化MyApplication类,而不是默认的Application类。在AndroidMainifest.xml文件的标签下进行指定就可以了。

android:name="com.example.hl.MyApplication"

 

这样就已经实现了一种全局获取Context的机制,之后想在项目中使用Application的Context时,只需调用一下MyApplication.getContext()就可以了。

避免context相关的内存泄露,记住以下几点:
1. 不要让生命周期长的对象引用activity context,即保证引用activity的对象要与activity本身生命周期是一样的
2. 对于生命周期长的对象,可以使用application context
3. 避免非静态的内部类,尽量使用静态类,避免生命周期问题,注意内部类对外部对象引用导致的生命周期变化

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/401974.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android 四大组件 —— 广播(广播机制解析)

在网络通信中&#xff0c;一个IP网络范围中最大的IP 地址是被保留作为广播地址来使用的。比如某个网络的IP 范围是192.168.0.XXX&#xff0c;子网掩码是255.255.255.0&#xff0c;那么这个网络的广播地址就是192.168.0.255。广播数据包会被发送到同一网络上的所有端口&#xff…

Android 基础 —— 活动的生存周期

一、返回栈 Android 中的活动是可以层叠的。我们每启动一个新的活动&#xff0c;就会覆盖在原活动之上&#xff0c;然后点击Back 键会销毁最上面的活动&#xff0c;下面的一个活动就会重新显示出来。 其实Android 是使用任务&#xff08;Task&#xff09;来管理活动的&#xff…

产品经理做市场调研和数据分析的方法

产品经理&#xff0c;你对用户的需求了解多少呢&#xff1f;你知道用户想要什么样的产品吗&#xff1f;你想知道用户将会如何看待你的产品吗&#xff1f;你想知道你设计的产品在用户中的口碑如何吗&#xff1f; 是 的。每一个产品经理都希望在产品开始立项设计前&#xff0c;得…

Android 基础 —— 活动的启动模式

活动的启动模式来说应该是个全新的概念&#xff0c;在实际项目中我们应该根据特定的需求为每个活动指定恰当的启动模式。启动模式一共有四种&#xff0c;分别是standard、singleTop、singleTask 和singleInstance &#xff0c; 可以在AndroidManifest.xml 中通过给<activity…

Android 四大组件 —— 服务

一、服务是什么 服务&#xff08;Service&#xff09;是Android 中实现程序后台运行的解决方案&#xff0c;它非常适合用于去执行那些不需要和用户交互而且还要求长期运行的任务。服务的运行不依赖于任何用户界面&#xff0c;即使当程序被切换到后台&#xff0c;或者用户打开了…

Highlighting System

Highlighting System 法线贴图漫反射着色器 Unity论坛&#xff1a;http://forum.unity3d.com/threads/143043-Highlighting-System-Released 需要条件 Requires Unity 3.5.6 or higher.This package requires Unity Pro, as it uses post-processing!Now supports Unity iOS Pr…

Android 基础 —— 模拟实现拨打电话功能

前面已经学习活动的显示跳转及隐式跳转&#xff0c;也学习 TextView 及 Button 两个控件的使用&#xff0c;下面我们来学习 EditText的使用&#xff1a; EditText 是程序用于和用户进行交互的另一个重要控件&#xff0c;它允许用户在控件里输入和编辑内容&#xff0c;并可以在程…

Android 四大组件 —— 活动(活动的隐式跳转)

上一篇我们讨论了活动的显示跳转&#xff0c;现在来学习活动的隐式跳转 相比于显式Intent&#xff0c;隐式Intent 则含蓄了许多&#xff0c;它并不明确指出我们想要启动哪一个活动&#xff0c;而是指定了一系列更为抽象的action 和category 等信息&#xff0c;然后交由系统去分…

ALAssetsLibrary-代码操作iOS相册资源

2019独角兽企业重金招聘Python工程师标准>>> 在iOS中&#xff0c;我们调用摄像头和选择相册中的资源&#xff0c;我们可以使用&#xff1a;UIImagePickerController类来完成。 当然&#xff0c;我们也可以不使用UI的形式来访问iOS设备的相册资源。 那就是使用&#…

Android 四大组件 —— 活动(使用Intent 实现活动的显示跳转)

一、什么是Intent&#xff1f;Intent的中文意思是目的。在Android中也是“目的”的意思。就是我们要去哪里&#xff0c;从这个activity要前往另一个Activity就需要用到Intent。 下面是 Intent 两个最基本的函数&#xff1a; 1、定义一个Intent [java] view plaincopy Intent in…

Android 项目在Eclipse中的目录结构

Android工程目录 如果使用Eclipse插件ADT开发应用程序&#xff0c;必须要熟悉工程的目录结构&#xff0c;清楚各个目录下面放置的是什么东西。Android工程主要的目录有&#xff1a;src、bin、gen、res等。 不同的Android平台目录结构是不同的&#xff0c;下面以Android 2.3.…

Exynos4412 Uboot 编译工具 —— 交叉工具链 arm-linux-gcc 的安装

一、什么是交叉编译&#xff1f; 在开发主机运行编译器编译内核、应用程序。内核和程序在目标机上运行&#xff0c;这个编译过程被称为交叉编译。编译器运行在开发主机&#xff08;通常是X86体系的PC机&#xff09;上&#xff0c;编译出的的代码是目标机体系结构的&#xff0c;…

Linux学习之CentOS(一)--CentOS6.4环境搭建

一、前言作为一个想从事j2ee后台开发的程序猿&#xff0c;linux系统怎能不学呢&#xff1f;所以&#xff0c;这几天自己准备学习一下linux操作系统。废话不多说&#xff0c;直奔主题。要学linux开发&#xff0c;首先得要安装linux系统吧&#xff0c;这里我在选择之前也挺迷茫&a…

内联函数 —— C 中关键字 inline 用法解析

一、什么是内联函数 在C语言中&#xff0c;如果一些函数被频繁调用&#xff0c;不断地有函数入栈&#xff0c;即函数栈&#xff0c;会造成栈空间或栈内存的大量消耗。 为了解决这个问题&#xff0c;特别的引入了inline修饰符&#xff0c;表示为内联函数。 栈空间就是指放置程式…

eclipse maven scm

http://my.oschina.net/OutOfMemory/blog/178512 1.安装eclipse的maven插件 m2e(http://wiki.eclipse.org/M2E_updatesite_and_gittags)Help->Install New Software...在work with中填入我们需要安装m2e的版本url&#xff1a;http://download.eclipse.org/technology/m2e/…

DS18B20 驱动编写

嵌入式开发平台&#xff1a;mini2440 DS18B20 所用GPIO&#xff1a;S3C2410_GPF(3) 一、DS18B20 时序分析 DS18B20的一线工作协议流程是&#xff1a;初始化→ROM操作指令→存储器操作指令→数据传输&#xff0c;其工作时序包括&#xff1a;初始化时序、写时序、读时序。 1、初…

Android 自定义View实现画背景和前景(ViewGroup篇)

2019独角兽企业重金招聘Python工程师标准>>> 在定义ListView的Selector时候&#xff0c;有个drawSelectorOnTop的属性&#xff0c;如果drawSelectorOnTop为true的话&#xff0c;Selector的效果是画在List Item的上面&#xff08;Selector是盖住了ListView的文字或者…

Linux的mmap内存映射机制解析

在讲述文件映射的概念时,不可避免的要牵涉到虚存(SVR 4的VM).实际上,文件映射是虚存的中心概念, 文件映射一方面给用户提供了一组措施,好似用户将文件映射到自己地址空间的某个部分,使用简单的内存访问指令读写文件&#xff1b;另一方面,它也可以用于内核的基本组织模式,在这种…

svn add Default@2x.png的文件含有@的文件名注意事项

为什么80%的码农都做不了架构师&#xff1f;>>> iOS的Icon里面&#xff0c;包含符号 &#xff0c;svn add Icon2x.png&#xff0c;没法加进去。 解决的办法是&#xff0c;在文件名最后加一个&#xff0c;例如 svn add Icon2x.png 或者svn add Icon\2x.png\ 转载于…

Linux 设备驱动的固件加载

作为一个驱动作者, 你可能发现你面对一个设备必须在它能支持工作前下载固件到它里面. 硬件市场的许多地方的竞争是如此得强烈, 以至于甚至一点用作设备控制固件的 EEPROM 的成本制造商都不愿意花费. 因此固件发布在随硬件一起的一张 CD 上, 并且操作系统负责传送固件到设备自身…