欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

android中this、getAppliaction()、context的区别。

程序员文章站 2024-01-24 20:11:40
...

android中this、getAppliaction()、context的区别。

@(android中的小知识)[this|getApplication| context]

在日常的android开发中,我们经常会跟this、getApplication()、context、getApplicationContext()打交道,平时疏于理解,想什么就用什么,今天我们来深入探究,具体来分析分析它们之间的不同。

  • this
    同Java中的this用法一样,this一般常用的方式就是对当前对象的引用。
    当然,我们也可以用this来表示类的成员变量,从而跟我们定义的函数中参数同名的变量用以区分。
    this也常用在类的构造方法中来引用满足指定参数类型的构造器。

public class Count {

    /**
     * @param args
     * 
     * 
     */


      private String name;
        private int number;   //这是类的成员变量

        public Count(String name){

        }
        public Count(String name, int number) {
            this(name);  //->表示调用一个参数的构造器。

            this.number =number+6;  //this.number->类的成员变量。 number->构造器的参数变量
            System.out.println("this.number ="+this.number+"---number="+number);
        }



    public static void main(String[] args) {

        Count count = new Count("aa", 1);

        // TODO Auto-generated method stub

    }

}

如上图,我们运行程序,在控制台看到的输出结果为:

android中this、getAppliaction()、context的区别。
这里需要注意的是:使用this(name);来表示调用一个参数的构造器时,该代码必须在此构造器方法的第一行,不然会报Constructor call must be the first statement in a constructor的错误。
android中this、getAppliaction()、context的区别。

  • 类名.this
    在android开发中,我们经常会使用如下的形式:
    我们在一个类的内部使用this,表示的是对该类的中当前对象的引用。而

  • context
    相信大家在日常的android代码编写过程中会经常的用到Contxt。context顾名思义就是上下文、场景的意思,我们用它来获取系统服务、加载资源、 获取内部文件路径等等。
    我们找到Context的源码

/**
 * Interface to global information about an application environment.  This is
 * an abstract class whose implementation is provided by
 * the Android system.  It
 * allows access to application-specific resources and classes, as well as
 * up-calls for application-level operations such as launching activities,
 * broadcasting and receiving intents, etc.
 */
public abstract class Context {
    /**
     * File creation mode: the default mode, where the created file can only
     * be accessed by the calling application (or all applications sharing the
     * same user ID).
     * @see #MODE_WORLD_READABLE
     * @see #MODE_WORLD_WRITEABLE
     */
    public static final int MODE_PRIVATE = 0x0000;

    public static final int MODE_WORLD_WRITEABLE = 0x0002;

    public static final int MODE_APPEND = 0x8000;

    public static final int MODE_MULTI_PROCESS = 0x0004;

    .
    .
    .
    }

我们从上面源码的注释可以看出Context是一个抽象类,提供了关于应用环境全局信息的接口。它允许获取以应用为特征的资源和类型,是一个统领一些资源(应用程序环境变量等)的上下文。
android中this、getAppliaction()、context的区别。
从上面的类图中我们可以看出,Activity、Application、Service都是其的间接子类。
- Context的使用(getContext()和getApplicationContext())

TextView tv = new TextView(getContext());

ListAdapter adapter = new SimpleCursorAdapter(getApplicationContext(), ...);

AudioManager am = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);getApplicationContext().getSharedPreferences(name, mode);

getApplicationContext().getContentResolver().query(uri, ...);

getContext().getResources().getDisplayMetrics().widthPixels * 5 / 8;

getContext().startActivity(intent);

getContext().startService(intent);

getContext().sendBroadcast(intent);

从上面的各种使用方式中我们可以看到Context的使用多种多样,但是它的使用还是要遵循一定的规则,不能想用什么就用什么。不然会造成意想不到的后果,这个我们在后面再说。
在绝大多数的场景下,Activity、Service以及Application这三种类型的Context对象都是可以通用的,不过有几种场景比较特殊,比如启动Activity,还有弹出Dialog。出于安全原因的考虑,Android是不允许Activity或Dialog凭空出现的,一个Activity的启动必须要建立在另一个Activity的基础之上,也就是以此形成的返回栈。而Dialog则必须在一个Activity上面弹出(除非是System Alert类型的Dialog),因此在这种场景下,我们只能使用Activity类型的Context,否则将会出错。
android中this、getAppliaction()、context的区别。

  • Context的获取方式和作用域
    要想获取Context对象,主要有以下的四种方法:

1.View.getContext,返回当前View的Context对象,通常是当前正在展示的Activity对象。作用域为此Activity内。
2.Activity.getApplicationContext,获取当前Activity所在应用的Context对象。这个Context的作用域为整个应用程序内。
3.ContextWrapper.getBaseContext(),用来获取一个ContextWrapper进行装饰之前的Context,它的作用是在另一个Context中访问context.获得的是一个Activity的Context对象。不怎么常用。这里我们举个例子特别说明下(布局界面很简单,就一个Button这里再不列出xml布局):

package com.example.yyh.test;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
    private Button btn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btn = (Button) findViewById(R.id.btn);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
               // Toast.makeText(this,"this的toast",Toast.LENGTH_LONG).show(); //---》错误,不能使用this



              Toast.makeText(getBaseContext(),"getBaseContext的toast"+getBaseContext(),Toast.LENGTH_LONG).show();//->正确


                Toast.makeText(getApplicationContext(),"getApplicationContext的toast"+getApplicationContext(),Toast.LENGTH_LONG).show();//--》正确



            }
        });
    }
}

第一个Toast报出的错误如下:
android中this、getAppliaction()、context的区别。
因为使用Toast第一个参数必须为一个Context对象,而这里传入的this,实际指的是onClick()方法中的参数View对象,所以报错。(对this不熟悉的可以看看文章开头所讲的this)
我们再看看后面两个Toast中的context,,看看其中的不同。
android中this、getAppliaction()、context的区别。
android中this、getAppliaction()、context的区别。
可以看出,一个是ContextImpl中的Context,返回的是Activity中的Context;一个是Application中的Context。返回的是应用程序的Context。从上面我们分析的Context类图中可以看到,Context抽象类有两个具体的实现类。geBaseContext()是ContextImpl类中的方法,而getApplicationContext()是ContextWrapper的子类Application中的方法。

4.使用this(Activity.this)获得是Acitvity中的context,它的作用域是Activity.

  • Context使用隐患
    这么多能获得Context对象的方式,我们要慎重选择,因为如果没有考虑清楚,很可能会引起内存泄露的问题。
    例如我们自定义的一个MyActivityManager:
public class MyActivityManager{
//定义的一个单例activity管理类
    private static MyActivityManager sInstance;
  private Context mContext;

    public static MyActivityManager getInstance(Context context) {
        if (sInstance == null) {
            synchronized(MyActivity.class){
                if(sInstance == null){
                      // 这个类拥有了一个静态的context引用   

            sInstance = new MyActivityManager(context);

                }

            }

        }

        return sInstance;
    } 

    private MyActivityManager(Context context) {
        mContext = context;
    }
}

然后我们在Activity中应用它:

public class MyActivity extends Activity{  

    private MyActivityManager manager = null;  


    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        //...layout 初始化  
        manager = MyActivityManager.getInstance(this);  
    }  


}  

由于MyActivityManager是单例模式,这个类的 生命周期属于整个应用程序,如果这个时候我们关闭了MyActivity,android进行GC操作,但是由于manager仍然引用了MyActivity(在sInstance = new MyActivityManager(context);),从而导致MyActivity不能被系统回收,造成内存泄露。解决的方式有两种:
1.使用正确的Context

public class MyActivityManager{
//定义的一个单例activity管理类
    private static MyActivityManager sInstance;
  private Context mContext;

    public static MyActivityManager getInstance(Context context) {
        if (sInstance == null) {
            synchronized(MyActivity.class){
                if(sInstance == null){
                      // 这个类拥有了一个静态的context引用   
            /**
             *这里我们进行一些改变,将context转变为context.getApplicationContext()
             *
             */     
            sInstance = new MyActivityManager(context.getApplicationContext());

                }

            }

        }

        return sInstance;
    } 

    private MyActivityManager(Context context) {
        mContext = context;
    }
}

还有可以在MyActivity中进行改变:

public class MyActivity extends Activity{  

    private MyActivityManager manager = null;  


    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        //...layout 初始化  
         /**
             *这里我们进行一些改变,将context转变为getApplicationContext()
             *
             */     
        manager = MyActivityManager.getInstance(getApplicationContext());  
    }  


}  

2.使用弱引用
重新改造单例Activity管理类:

public class MyActivityManager{
//定义的一个单例activity管理类
    private static MyActivityManager sInstance;
  private WeakReference<Context> mWRContext;

    public static MyActivityManager getInstance(Context context) {
        if (sInstance == null) {
            synchronized(MyActivity.class){
                if(sInstance == null){
                      // 这个类拥有了一个静态的context引用   

            sInstance = new MyActivityManager(context);

                }

            }

        }

        return sInstance;
    } 

    private MyActivityManager(Context context) {
        mWRContext = new WeakRefence<Context>(context);
    }
}

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

参考
- [Context都没弄明白,还怎么做Android开发?]:http://www.jianshu.com/p/94e0f9ab3f1d