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

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

    }

}

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

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

  • 类名.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是一个抽象类,提供了关于应用环境全局信息的接口。它允许获取以应用为特征的资源和类型,是一个统领一些资源(应用程序环境变量等)的上下文。
Alt text
从上面的类图中我们可以看出,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,否则将会出错。
Alt text

  • 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报出的错误如下:
Alt text
因为使用Toast第一个参数必须为一个Context对象,而这里传入的this,实际指的是onClick()方法中的参数View对象,所以报错。(对this不熟悉的可以看看文章开头所讲的this)
我们再看看后面两个Toast中的context,,看看其中的不同。
Alt text
Alt text
可以看出,一个是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

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值