`
亮0000仔
  • 浏览: 12326 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
文章分类
社区版块
存档分类
最新评论

Android中的Context详解

 
阅读更多
Android中的Context详解(2012-07-23 14:21)

Android基础概念Context的作用

Context字面意思上下文,位于framework package的android.content.Context中,其实该类为LONG型,类似Win32中的Handle句柄,很多方法需要通过Context才能识别调用者的实例,比如说Toast的第一个参数就是Context,一般在Activity中我们直接用this代替,代表调用者的实例为Activity,而到了一个button的onClick(View view)等方法时,我们用this时就会报错,所以我们可能使用ActivityName.this来解决,主要原因是因为实现Context的类主要有Android特有的几个模型,Activity、Service以及BroadcastReceiver。 常规需要Context实例的方法主要有各种Service实现的类,比如说SensorManager在实例化时需要getSystemService(String)方法就必须由Context的实例执行,还有一些私有的文件系统I/O比如说openFileInput以及常用的Toast的makeText方法。

android context理解

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

点击(此处)折叠或打开

  1. protected void onCreate(Bundle state) {
  2. super.onCreate(state);
  3. TextView label = newTextView(this);
  4. //传递context给view control
  5. label.setText("Leaks are bad");
  6. setContentView(label);
  7. }
把activity context传递给view,意味着view拥有一个指向activity的引用,进而引用activity占有的资源:view hierachy, resource等。 这样如果context发生内存泄露的话,就会泄露很多内存。 这里泄露的意思是gc没有办法回收activity的内存。 Leaking an entire activity是很容易的一件事。 当屏幕旋转的时候,系统会销毁当前的activity,保存状态信息,再创建一个新的。 比如我们写了一个应用程序,它需要加载一个很大的图片,我们不希望每次旋转屏 幕的时候都销毁这个图片,重新加载。实现这个要求的简单想法就是定义一个静态的Drawable,这样Activity 类创建销毁它始终保存在内存中。 实现类似:

点击(此处)折叠或打开

  1. publicclassmyactivityextendsActivity{
  2. privatestaticDrawable sBackground;
  3. protectedvoidonCreate(Bundlestate){
  4. super.onCreate(state);
  5. TextViewlabel=newTextView(this);
  6. label.setText("Leaks are bad");
  7. if(sBackground==null){
  8. sBackground=getDrawable(R.drawable.large_bitmap);
  9. }
  10. label.setBackgroundDrawable(sBackground);
  11. //drawable attached to a view
  12. setContentView(label);
  13. }
  14. }


这段程序看起来很简单,但是却问题很大。当屏幕旋转的时候会有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.getApplication方法获取。 避免context相关的内存泄露,记住以下几点:1. 不要让生命周期长的对象引用activity context,即保证引用activity的对象要与activity本身生命周期是一样的2. 对于生命周期长的对象,可以使用application context3. 避免非静态的内部类,尽量使用静态类,避免生命周期问题,注意内部类对外部对象引用导致的生命周期变化

根据packageName构造Context

通常情况下获取当前应用的context的方法是getApplicationContext, 但是通过根据其他的packageName如何构造 Context呢?Android平台的应用实例其实还可以通过其他方式构造。
比如代码:

点击(此处)折叠或打开

  1. try {
  2. Context ctx=createPackageContext("com.android123.Cwj", 0);
  3. //ctx已经是com.android123.cwj的实例
  4. } catch(NameNotFoundException e) {
  5. //可能由于 pacakgeName不存在所以必须处理该异常
  6. }
需要注意的是,createPackageContext方法的第二个参数可选为CONTEXT_INCLUDE_CODE 和 CONTEXT_IGNORE_SECURITY , 定义分别为4和2,上面为0。一般忽略安全错误问题可以通过CONTEXT_IGNORE_SECURITY 标记, 同时可能还需要处理 SecurityException 异常.

Android Context应该怎么写?


如果想要弹出一个AlertDialog,要写如下的代码

点击(此处)折叠或打开

  1. AlertDialog.Builder alert=newAlertDialog.Builder(this);
  2. alert.setTitle("Warning");
  3. alert.setMessage("Wrong time!");
  4. alert.show();
这里构造方法的原型是AlertDialog.Builder(Context arg) 需要一个Context类的对象作为参数,一般我们都在Activity里写,所以用this,表示在当前的会话中弹出AlertDialog。 在我的一个程序里,我自定义了一个接口PublicinterfaceCustomPickerListener,在实现这个接口的方法时我需要弹出来一个AlertDialog,这里,参数表里填写this的话会提示错误:The constructor AlertDialog.Builder(newCustomPickerListener(){})isundefined.其实这个地方写this很明显是错误的,但是要写什么才能达成目的呢? 官方文档上对context的解释是
Interface toglobalinformation about an application environment. Thisisanabstractclasswhose implementationisprovided by the Android system. It allows access to application-specific resources and classes,aswellasup-callsforapplication-level operations suchaslaunching activities, broadcasting and receiving intents, etc.
于是我就试着写上了我程序的 包.目标类.this,如下
AlertDialog.Builder alert=newAlertDialog.Builder(com.android.alcoholtest.AlcoholTest.this);
然后就成功了

Android中Activity共享变量的另一方法:Application context


Android中在不同Activity中传递变量,通常使用Intent中Bundle添加变量的操作方法。   

点击(此处)折叠或打开

  1. Intent intent=newIntent();
  2. intent.setClass(A.this,B.class);
  3. Bundle bundle=newBundle();
  4. bundle.putString("Info","Information");
  5. intent.putExtras(bundle);
  6. startActivity(intent);
  7. Intent   intent=newIntent();
  8. intent.setClass(A.this,B.class);
  9. Bundle bundle=newBundle();
  10. bundle.putString("Info","Information");
  11. intent.putExtras(bundle);
  12. startActivity(intent);

  13.   
不过在多个Activity中经常使用同一变量时,使用Bundle则比较麻烦,每次调用Activity都需要设置一次。  如想在整个应用中使用,在java中一般是使用静态变量,而在android中有个更优雅的方式是使用Application context。   新建一个类,继承自Application

点击(此处)折叠或打开

  1. classMyAppextendsApplication{
  2. privateStringmyState;
  3. publicStringgetState(){
  4. returnmyState;  
  5. }
  6. publicvoidsetState(Strings){
  7. myState=s;  
  8. }  
  9. }  
  在AndroidManifest.xml的application加个name属性就可以了,如下面所示:

点击(此处)折叠或打开

  1. android:name=".MyApp"
  2. android:icon="@drawable/icon"  
  3. android:label="@string/app_name">
  使用时:

点击(此处)折叠或打开

  1. classBlahextendsActivity{
  2. @Override  
  3. publicvoidonCreate(Bundle b){
  4.   ...
  5.   MyApp appState=((MyApp)getApplicationContext());
  6.    Stringstate=appState.getState();  ...
  7.   }
  8. }

  9.   
  英文引用:
http://stackoverflow.com/questions/708012/android-how-to-declare- global-variables   The more general problem you are encounteringishow to save stateacross several Activities and all parts of your application. A staticvariable (forinstance, a singleton)isa common Java way of achievingthis. I have found however, that a more elegant wayinAndroidistoassociate your state with the Application context.   
--如想在整个应用中使用,在java中一般是使用静态变量,而在android中有个更优雅的方式是使用Application context。  
 As you know, each Activityisalso a Context, whichisinformationabout its execution environmentinthe broadest sense. Your applicationalso has a context, and Android guarantees that it will existasasingle instance across your application.  
 --每个Activity 都是Context,其包含了其运行时的一些状态,android保证了其是single instance的。
 The way todothisisto create your own subclass of android.app.Application,and then specify thatclassinthe application taginyour manifest.Now Android will automatically create an instance of thatclassandmake it availableforyour entire application. You can access it fromany contextusingthe Context.getApplicationContext() method (Activityalso provides a method getApplication() which has the exact sameeffect):   --方法是创建一个属于你自己的android.app.Application的子类,然后在manifest中申明一下这个类,这是 android就为此建立一个全局可用的实例,你可以在其他任何地方使用Context.getApplicationContext()方法获取这个实例,进而获取其中的状态(变量)。

[小技巧]在任意位置获取应用程序Context - [Android学习笔记]

Android程序中访问资源时需要提供Context,一般来说只有在各种component中(Activity, Provider等等)才能方便的使用api来获取Context, 而在某些工具类中要获取就很麻烦了。为此,我们可以自定义一个Application类来实现这种功能。

点击(此处)折叠或打开

  1. importandroid.app.Application;
  2. publicclassMyApplicationextendsApplication{
  3. privatestaticMyApplication instance;
  4. publicstaticMyApplicationgetInstance(){returninstance;}
  5. @Override
  6. publicvoidonCreate(){
  7. // TODO Auto-generated method stub
  8. super.onCreate();
  9. instance=this;
  10. }
  11. }
然后在manifest中<application>中加入name="mypackage.MyApplication"就可以在任意类中使用MyApplication.getInstance()来获取应用程序Context了。

Android获取其他包的Context实例然后干坏事

Android中有Context的概念,想必大家都知道。Context可以做很多事情,打开activity、发送广播、打开本包下文件夹和数据库、获取classLoader、获取资源等等。如果我们得到了一个包的Context对象,那我们基本上可以做这个包自己能做的大部分事情。 那我们能得到吗?很高兴的告诉你,能! Context有个createPackageContext方法,可以创建另外一个包的上下文,这个实例不同于它本身的Context实例,但是功能是一样的。 这个方法有两个参数:1。packageName 包名,要得到Context的包名2。flags 标志位,有CONTEXT_INCLUDE_CODE和CONTEXT_IGNORE_SECURITY两个选项。CONTEXT_INCLUDE_CODE的意思是包括代码,也就是说可以执行这个包里面的代码。CONTEXT_IGNORE_SECURITY的意思是忽略安全警告,如果不加这个标志的话,有些功能是用不了的,会出现安全警告。下面给个小例子,执行另外一个包里面的某个类的方法。 另外一个包的包名是chroya.demo,类名Main,方法名print,代码如下:

点击(此处)折叠或打开

  1. packagechroya.demo;
  2. importandroid.app.Activity;
  3. importandroid.os.Bundle;
  4. importandroid.util.Log;
  5. classMainextendsActivity{
  6. @Override
  7. publicvoidonCreate(Bundle savedInstanceState){
  8. super.onCreate(savedInstanceState);
  9. }
  10. publicvoidprint(Stringmsg){
  11. Log.d("Main","msg:"+msg);
  12. }
  13. }
本包的调用Main的print方法的代码块如下:

点击(此处)折叠或打开

  1. Contextc=createPackageContext("chroya.demo",
  2. Context.CONTEXT_INCLUDE_CODE|Context.CONTEXT_IGNORE_SECURITY);
  3. //载入这个类
  4. Classclazz=c.getClassLoader().loadClass("chroya.demo.Main");
  5. //新建一个实例
  6. Objectowner=clazz.newInstance();
  7. //获取print方法,传入参数并执行
  8. Objectobj=clazz.getMethod("print",String.class).invoke(owner,"Hello");

ok,这样,我们就调用了chroya.demo包的Main类的print方法,执行结果,打印出了Hello。 怎么样,这只是一个调用其他包的代码的例子,我们获取到Context,还可以做很多事情,当然,题目所说的坏事,还是不要做为好。
分享到:
评论

相关推荐

    android中Context深入详解

    Android 中 Context 深入详解 Context 是 Android 中一个非常重要的概念,它是 Android 应用程序的核心组件之一。Context 提供了许多有用的方法和变量,用于访问应用程序的资源和组件。本文将深入探讨 Android 中 ...

    android_context详解

    ### Android Context详解 在Android应用开发中,`Context`是一个至关重要的概念,它如同一个纽带,连接着应用的各个组成部分,如Service、BroadcastReceiver、Activity等。本文将深入剖析`Context`的内部机制,帮助...

    android优化技术详解

    Android 优化技术详解 Android 优化技术是指通过合理的编程和设计来提高 Android 应用程序的性能、内存和用户体验的一系列技术。下面是 Android 优化技术的详细解释: UI 布局优化 Android 的 UI 界面布局的优化...

    Android 中Context的使用方法详解

    Android 中Context的使用方法详解 Context 是 Android 中一个非常重要的概念,它提供了关于应用环境全局信息的接口,它是一个抽象类,它的执行被 Android 系统所提供。 Context 的主要作用是提供了关于应用环境全局...

    Android中上下文(context)用法详解

    ### Android中上下文(context)用法详解 #### 一、Context基本概念 **Context** 是 Android 开发中一个非常核心且重要的概念。它提供了一系列方法来帮助开发者访问应用程序的各种资源和服务。 - **定义**: `...

    Android context源码详解及深入分析

    Android Context 是Android应用程序开发中的一个核心概念,它代表了应用程序的上下文环境,是一个与系统交互的关键接口。Context主要用于加载资源、启动Activity、获取系统服务、创建View等操作。在Android系统中,...

    Android全局获取Context实例详解

    Android全局获取Context实例详解 Android全局获取Context实例是Android开发中一个常见的问题。Context是Android中一个非常重要的概念,它提供了访问应用程序级别的资源和服务的能力。获取Context实例是非常必要的,...

    Android编程中context及全局变量实例详解

    本文实例讲述了Android编程中context及全局变量的用法。分享给大家供大家参考,具体如下: 今天在研究context的时候,对application和activity context有了一定的了解,下面是从网上复制过来的资料 Application ...

    android adapter详解

    Android Adapter 详解 Android Adapter 是 Android 开发中一个重要的组件,负责将数据绑定到用户界面中。今天,我们将深入探讨 Android Adapter 的原理和实现方式。 什么是 Android Adapter? Android Adapter 是...

    安卓Android Context类实例详解

    在Android开发中,Context类是应用的核心组成部分,它提供了与应用程序环境交互的接口。Context类在许多场景下被使用,包括创建UI元素、访问系统服务、读取资源以及执行其他与应用程序上下文相关的操作。本篇文章将...

    详解Android中的Context抽象类

    在Android开发中,Context是一个至关重要的抽象类,它扮演着应用程序环境信息的角色,提供了一系列用于访问应用程序资源和执行应用级别操作的方法。理解Context的工作原理对于深入Android开发至关重要。以下是对...

    Android广播机制详解

    在Android系统中,广播(Broadcast)是一种非常重要的组件,它使得应用程序之间能够进行无须先建立连接的通信。本文将详细解析Android广播机制的核心概念、工作原理以及如何使用。 一、广播基本概念 1. 广播Intent...

    Android的Window类详解

    ### Android的Window类详解 #### 一、概述 在Android开发过程中,`Window`类扮演着极其重要的角色,它是应用程序与用户交互的主要界面之一。本文将深入探讨Android系统的`Window`类,包括其属性和成员函数等内容。...

    Android服务Service详解

    【Android服务Service详解】 在Android应用开发中,Service是四大组件之一,用于执行长时间运行的任务,如后台音乐播放、网络数据下载等。Service不同于Activity,它没有用户界面,但可以在后台持续运行,即使用户...

    Android内存泄漏详解专栏

    ### Android内存泄漏详解 #### 一、什么是内存泄漏? 内存泄漏是指程序中已分配的内存未得到及时释放或无法释放,导致系统中的可用内存逐渐减少,最终可能导致应用程序或整个系统运行缓慢甚至崩溃。 #### 二、...

    Android服务Service_详解.pdf

    Android服务(Service)是Android操作系统中四个核心应用程序组件之一,其他三个分别是Activity、BroadcastReceiver和ContentProvider,它们在Android应用开发中的作用和使用场景各不相同。Service的作用主要体现在...

    android各组件详解- Intent.

    标题与描述均指向了“Android各组件详解——Intent”,这一主题深入探讨了Android开发中至关重要的Intent组件。本文将从多个角度解析Intent的功能、应用场景及其内部结构,为开发者提供全面的理解。 ### Intent概述...

    Android--详解安卓中的Menu.rar

    本资源"Android--详解安卓中的Menu.rar"可能包含了一系列关于如何在Android应用中设计和实现Menu的教程、示例代码和讲解文档。虽然无法一一验证所有内容,但它们可以作为学习和参考的宝贵资料。 1. **Menu的基本...

Global site tag (gtag.js) - Google Analytics