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,一经查实,立即删除!

相关文章

函数可微的一个充分条件

设函数 $f:\bbR^n\to \bbR$ 在 $\bbR^n\bs \sed{0}$ 可微, 在 $0$ 连续, 且 $$\bex\lim_{\bbx\to0}\frac{\p f(\bbx)}{\p x_i}0,\ i1,2,\cdots,n. \eex$$ 证明 $f$ 在 $0$ 可微. 证明: 由 $$\beex \bea |f(\bbx)-f(0)| &\leq |f(x_1,x_2,\cdots,x_n)-f(0,x_2,\cdots,x_n)|…

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

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

linux高可用

来自&#xff1a;http://blog.csdn.net/deansrk/article/details/6780639Linux高可用集群&#xff08;一&#xff09;&#xff1a;Corosync/Openais Pacemaker 实现高可用集群来自&#xff1a;http://blog.csdn.net/deansrk/article/details/6780650Linux高可用集群&#xff0…

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…

一个行外人看中国的电子竞技

本身爱打游戏&#xff0c;也经常关注一下主流页媒的公告&#xff0c;想以一个行外人谈一下中国的电子竞技。先解释一个概念&#xff0c;流入行业的钱就是一个资本蓄水池&#xff0c;在这个行业的各个环节都要从中分得一杯水来维持他发展&#xff0c;这就是资本注入的全灌溉。&a…

ExpandableListView 箭头靠右

ExpandableListView 默认标示箭头是在左边的&#xff0c;当左边有图片时&#xff0c;不是太好看&#xff0c;想把它放在右边&#xff0c;这么简单的事可我折腾死了&#xff0c;还好给我找到了。 参照了以下链接&#xff1a; expandableListview的默认箭头箭头怎样移到右边 提供…

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…

放学默示录Ⅰ:来!抠奖 移动游戏策划案

游戏名称&#xff1a;放学默示录游戏类型&#xff1a;休闲类 单机版带网络服务运营方式&#xff1a;道具收费&#xff0c;捐赠。游戏背景&#xff1a;以学生放学后的小摊游艺为参考。游戏玩法&#xff1a;游戏分为默示录模式&#xff0c;日常模式&#xff0c;大赛模式&#xff…

mod_wsgi的工作模式和配置

Openstack所有提供API接口的服务都是python web server&#xff0c;而其本身性能很弱&#xff0c;目前已经将它们配置到了apache上。但对于如何设置mod_wsgi的参数&#xff0c;我一直没有好好去阅读其文档。 参考了mod_wsgi 的两种模式和Process and Thread两篇文章后&#xff…

Android 项目在Eclipse中的目录结构

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

怎样判断网页是静态还是伪静态呢

怎样判断网页是静态还是伪静态呢? SEO文章看多了&#xff0c;经常能听到静态、伪静态这类的词语&#xff0c;那什么样的网页是静态的&#xff0c;什么样的网页是伪静态的呢&#xff1f; IE5浏览器以上&#xff1a;打开你想判断的网站后&#xff0c;再在网址框中输入javascript…

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…