深入理解Context

  一直见面却不熟悉的陌生人

Posted by MrCodeSniper on January 22, 2018

Android应用模型是基于组件的应用设计模式,组件的运行要有一个完整的Android工程环境,在这个环境下,Activity、Service等系统组件才能够正常工作

Context的源码注释说明

Context提供了关于应用环境全局信息的接口,它是一个抽象类,它的执行为Android系统所提供

它允许获取以应用为特征的资源和类型,是一个统领一些资源(应用程序环境变量等)的上下文

Activity,Service,Application正是因为继承实现自Context

所以能执行一些获取资源的函数,例如getApplicationContext和getResources().getDrawable()根据id获取drawable资源

具体:弹出Toast、启动Activity、启动Service、发送广播、操作数据库,操作文件等等都需要用到Context。

Context相关成员

Context

Context类本身是一个纯abstract类,提供一些功能和静态常量的规范

ContextImpl

真正功能的实现类,接收到通过Binder机制 获取底层服务得来的参数赋于自身 并实现抽象方法

应用程序中所调用的各种Context类的方法,其实现均来自于该类

ContextWrapper

ContextWrapper类,如其名所言,这只是一个包装而已,

ContextWrapper构造函数中必须包含一个真正的Context引用,同时ContextWrapper中提供了attachBaseContext()用于给ContextWrapper对象中指定真正的Context对象

真正的context即实现过的ContextImpl,这样就能保证装饰类的子类也能拥有context提供的功能,在这基础上 装饰了其他功能

Service

Service是不需要主题的,因为Service是没有界面的后台场景,所以直接继承于ContextWrapper

startService和bindService实际的实现都是在ContextImpl中通过AMS调用底层service服务

service类在其基础上增加了一些管理和控制功能

Application

Application是用于保存全局应用状态的基础类,而且是单例模式,生命周期贯穿整个应用的运行

基于这一点,我们可以利用它的全局单例,保存一些系统运行时的状态信息,和初始化的动作

其中的方法大多是回调 利于我们在不同应用状态下开发

ContextThemeWrapper

如其名所言,其内部包含了与主题(Theme)相关的接口

这里所说的主题就是指在AndroidManifest.xml中通过android:theme为Application元素或者Activity元素指定的主题

在构造方法中传入主题资源,并根据资源做各自主题相关操作

Activity

Activity需要主题 继承自ContextThemeWrapper 可以操作Context资源 可以设置主题资源 并实现了各自接口 才使得四大组件之一的Activity显得十分重要

一个应用程序有几个Context

Context数量=activity个数+service个数+1

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作为静态对象常驻与内存,其生命周期要长于普通的对象

如果getInstance传入的是Activity 那么instance会持有activity引用 导致activity无法被销毁回收

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);
    }
}

在iv.setImageDrawable(mDrawable);设置drawable中进行了这个操作

mDrawable.setCallback(this); 静态的Drawable对象设置了对imageview的引用?老版本为强引用:新版本为弱引用 导致drawable->imageview->activity的引用链 导致无法回收

总结

context家族

Reference From:

Context都没弄明白,还怎么做Android开发?