美文网首页
Android-Context

Android-Context

作者: 有腹肌的豌豆Z | 来源:发表于2020-09-17 10:57 被阅读0次

一、什么是Context

Context 是什么?
  • 它描述的是一个应用程序环境的信息,即上下文。
  • 该类是一个抽象( abstract class )类, Android 提供了该抽象类的具体实 现类( ContextIml )。
  • 通过它我们可以获取应用程序的资源和类, 也包括一些应用级别操作, 例如:启动一个 Activity ,发送广播,接受 Intent ,信息,等。
源码中的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 {
}
附加一张 Context 继承关系图

二、相关类简介

  • Context
    Context类本身是一个纯abstract类,它有两个具体的实现子类:ContextImpl和ContextWrapper。

  • ContextWrapper
    其中ContextWrapper类,如其名所言,这只是一个包装而已,ContextWrapper构造函数中必须包含一个真正的Context引用,同时ContextWrapper中提供了attachBaseContext()用于给ContextWrapper对象中指定真正的Context对象,调用ContextWrapper的方法都会被转向其所包含的真正的Context对象。

  • ContextThemeWrapper
    ContextThemeWrapper类,如其名所言,其内部包含了与主题(Theme)相关的接口,这里所说的主题就是指在AndroidManifest.xml中通过android:theme为Application元素或者Activity元素指定的主题。

  • Activity/Service/Application
    当然,只有Activity才需要主题,Service是不需要主题的,因为Service是没有界面的后台场景,所以Service直接继承于ContextWrapper,Application同理。
    Activity,Application,Service虽都继承自ContextWrapper(Activity继承自ContextWrapper的子类ContextThemeWrapper),但它们初始化的过程中都会创建ContextImpl对象,由ContextImpl实现Context中的方法。

  • 而ContextImpl类则真正实现了Context中的所以函数,应用程序中所调用的各种Context类的方法,其实现均来自于该类。
    一句话总结:Context的两个子类分工明确,其中ContextImpl是Context的具体实现类,ContextWrapper是Context的包装类。


三、如何获取Context

  • View.getContext,返回当前View对象的Context对象,通常是当前正在展示的Activity对象。
  • Activity.getApplicationContext,获取当前Activity所在的(应用)进程的Context对象,通常我们使用Context对象时,要优先考虑这个全局的进程Context。
  • ContextWrapper.getBaseContext():用来获取一个ContextWrapper进行装饰之前的Context,可以使用这个方法,这个方法在实际开发中使用并不多,也不建议使用。
  • Activity.this 返回当前的Activity实例,如果是UI控件需要使用Activity作为Context对象,但是默认的Toast实际上使用ApplicationContext也可以。

四、Context作用域

  • 出于安全原因的考虑,Android是不允许Activity或Dialog凭空出现的,一个Activity的启动必须要建立在另一个Activity的基础之上,也就是以此形成的返回栈。
  • 而Dialog则必须在一个Activity上面弹出(除非是System Alert类型的Dialog),因此在这种场景下,我们只能使用Activity类型的Context,否则将会出错。
  • 凡是跟UI相关的,都应该使用Activity做为Context来处理;其他的一些操作,Service,Activity,Application等实例都可以,当然了,注意Context引用的持有,防止内存泄漏。



五、Context引起的内存泄露

但Context并不能随便乱用,用的不好有可能会引起内存泄露的问题,下面就示例两种错误的引用方式。
  • 错误的单例模式
public class Singleton {
    private static Singleton instance;
    private Context mContext;

    private Singleton(Context context) {
        this.mContext = context;
    }

    public static Singleton getInstance(Context context) {
        if (instance == null) {
            instance = new Singleton(context);
        }
        return instance;
    }
}

  • 这是一个非线程安全的单例模式,instance作为静态对象,其生命周期要长于普通的对象,其中也包含Activity,假如Activity A去getInstance获得instance对象,传入this,常驻内存的Singleton保存了你传入的Activity A对象,并一直持有,即使Activity被销毁掉,但因为它的引用还存在于一个Singleton中,就不可能被GC掉,这样就导致了内存泄漏。
View持有Activity引用
public class MainActivity extends Activity {
    private static Drawable mDrawable;

    @Override
    protected void onCreate(Bundle saveInstanceState) {
        super.onCreate(saveInstanceState);
        setContentView(R.layout.activity_main);
        ImageView iv = new ImageView(this);
        mDrawable = getResources().getDrawable(R.drawable.ic_launcher);
        iv.setImageDrawable(mDrawable);
    }
}

  • 有一个静态的Drawable对象当ImageView设置这个Drawable时,ImageView保存了mDrawable的引用,而ImageView传入的this是MainActivity的mContext,因为被static修饰的mDrawable是常驻内存的,MainActivity是它的间接引用,MainActivity被销毁时,也不能被GC掉,所以造成内存泄漏。

相关文章

  • Android Context笔记

    【转载】http://www.crazyjiang.cn/2016/09/25/android-context/ ...

  • Android-Context

    一、什么是Context Context 是什么? 它描述的是一个应用程序环境的信息,即上下文。 该类是一个抽象(...

  • Android-context

    1、context描述的是一个应用程序环境的信息,即上下文。是一个抽象类,它的实现由Android系统提供。通过它...

网友评论

      本文标题:Android-Context

      本文链接:https://www.haomeiwen.com/subject/kxnzektx.html