征服Android面试官路漫漫(三):从源码深扒一下四大组件和 Context

本文探讨了Android开发中的核心概念——Context,包括其作用、四大组件(Activity、Service、Application、ContentProvider)与Context的关系,特别是为何Application的Context不能创建Dialog。文章通过源码分析,解释了Context的创建过程,以及ContextWrapper和ContextImpl的角色。同时,提到了Context在不同组件中的使用差异,并介绍了如何通过理解Context来提升Android技能。
摘要由CSDN通过智能技术生成

目录

  • 什么是 Context?
  • 四大组件和 Context
  • Application 和 Context
  • 为什么 Application 的 Context 不可以创建 Dialog ?
  • 未完待续...

文章开头,先来看一段代码:

public class ContextActivity extends AppCompatActivity {

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

        Log.e("context", "getApplication in Activity: " + getApplication().getClass().getName());
        Log.e("context", "getApplicationContext in Activity: " + getApplicationContext().getClass().getName());
        Log.e("context", "getBaseContext in Activity: " + getBaseContext().getClass().getName());

        startService(new Intent(this,ContextService.class));
    }
}

你能准确的说出这三行打印语句的执行结果吗?如果不能,你需要认真阅读这篇文章。

什么是 Context ?

Context 是一个抽象类。既然是抽象类,那么它就代表了一类具体对象的通用特征。先来看一下 Context 的类图:

其中看到了我们很熟悉的 ActivityServiceApplication,这些都是 Context 的具体实现类,也就是说 Context 抽象了这些类的通用特征和功能:

  • 获取系统资源,getResources()getAssets() 等
  • 启动各种系统组件
  • 获取系统服务
  • ......

这些与系统环境息息相关的功能都是由 Context 提供的,所以一般将其称为上下文,它其实就是对当前运行环境的具体描述,为系统组件的正常运行提供必要的环境和资源。

在上面的类图中,可能有两个读者比较陌生的类,ContextWraaper 和ContextImpl

ContextImpl 很好理解,它就是 Context 的具体实现类。Context 类中的所有抽象方法都是在 ContextImpl 中实现的。


class ContextImpl extends Context {
    ......

   @Override
    public AssetManager getAssets() {
        return getResources().getAssets();
    }

    @Override
    public Resources getResources() {
        return mResources;
    }

    @Override
    public PackageManager getPackageManager() {
        if (mPackageManager != null) {
            return mPackageManager;
        }

        IPackageManager pm = ActivityThread.getPackageManager();
        if (pm != null) {
            // Doesn't matter if we make more than one instance.
            return (mPackageManager = new ApplicationPackageManager(this, pm));
        }

        return null;
    }

    @Override
    public ContentResolver getContentResolver() {
        return mContentResolver;
    }

    @Override
    public Looper getMainLooper() {
        return mMainThread.getLooper();
    }

    ......
}

ContextWraaper 其实也很简单,直接看它的实现代码:


public class ContextWrapper extends Context {
    @UnsupportedAppUsage
    Context mBase;

    public ContextWrapper(Context base) {
        mBase = base;
    }
    
    /**
     * 在这个方法中给 mBase 赋值
     */
    protected void attachBaseContext(Context base) {
        if (mBase != null) {
            throw new IllegalStateException("Base context already set");
        }
        mBase = base;
    }

    public Context getBaseContext() {
        return mBase;
    }

    @Override
    public AssetManager getAssets() {
        return mBase.getAssets();
    }

    @Override
    public Resources getResources() {
        return mBase.getResources();
    }

    ......
}

这是一个典型的 装饰者模式,也叫做 修饰模式,以下来自维基百科:

修饰模式,是面向对象编程领域中,一种动态地往一个类中添加新的行为的设计模式。就功能而言,修饰模式相比生成子类更为灵活,这样可以给某个对象而不是整个类添加一些功能。

通过使用修饰模式,可以在运行时扩充一个类的功能。原理是:增加一个修饰类包裹原来的类,包裹的方式一般是通过在将原来的对象作为修饰类的构造函数的参数。装饰类实现新的功能,但是,在不需要用到新功能的地方,它可以直接调用原来的类中的方法。修饰类必须和原来的类有相同的接口。

修饰模式是类继承的另外一种选择。类继承在编译时候增加行为,而装饰模式是在运行时增加行为。

当有几个相互独立的功能需要扩充时,这个区别就变得很重要。在有些面向对象的编程语言中,类不能在运行时被创建,通常在设计的时候也不能预测到有哪几种功能组合。这就意味着要为每一种组合创建一个新类。相反,修饰模式是面向运行时候的对象实例的,这样就可以在运行时根据需要进行组合。一个修饰模式的示例是JAVA里的Java I/O Streams的实现。

Context 是基本的抽象类,无论是实现类,还是装饰类,都直接或间接的实现它。ContextImpl 是 Context 的直接实现类,但各个组件并不是直接继承 ContextImpl,而是通过装饰类 ContextWrapper 来持有 C

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值