文章目录

  • Context 介绍
  • Context数量
  • getContext()、getApplication()、getApplicationContext()和getBaseContext()区别
    • getContext
    • getApplication()、getApplicationContext()
    • getBaseContext()

Context 介绍

Android程序不像Java程序一样,随便创建一个类,写个main()方法就能跑了,而是要有一个完整的Android工程环境,在这个环境下,我们有像Activity、Service、BroadcastReceiver等系统组件,而这些组件并不是像一个普通的Java对象new一下就能创建实例的了,而是要有它们各自的上下文环境,也就是我们这里讨论的Context。可以这样讲,Context是维持Android程序中各组件能够正常工作的一个核心功能类。

下面我们来看一下Context的继承结构:

直系子类有两个,一个是ContextWrapper,一个是ContextImpl。那么从名字上就可以看出,ContextWrapper是上下文功能的封装类,而ContextImpl则是上下文功能的实现类。而ContextWrapper又有三个直接的子类,ContextThemeWrapper、Service和Application。其中,ContextThemeWrapper是一个带主题的封装类,而它有一个直接子类就是Activity。

Context一共有三种类型,分别是Application、Activity和Service。这三个类虽然分别各种承担着不同的作用,但它们都属于Context的一种,而它们具体Context的功能则是由ContextImpl类去实现的。

Context数量

那么一个应用程序中到底有多少个Context呢?其实根据上面的Context类型我们就已经可以得出答案了。Context一共有Application、Activity和Service三种类型,因此一个应用程序中Context数量的计算公式就可以这样写

Context数量 = Activity数量 + Service数量 + 1

上面的1代表着Application的数量,因为一个应用程序中可以有多个Activity和多个Service,但是只能有一个Application。

getContext()、getApplication()、getApplicationContext()和getBaseContext()区别

getContext

就是代表当前上下文环境,这个是给View了提供的方法。返回的是当前View运行在哪个Activity Context中。


public class MainActivity extends AppCompatActivity {private static final String TAG = "MainActivity";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Button btn = findViewById(R.id.handler_btn);Context context = btn.getContext();// 如果说btn是在当前Activity调用的,那么这两个打印的结果是相同的,都是指的是MainActivity对象,它是一个Context。Log.d(TAG, "onCreate: "+context);Log.d(TAG, "onCreate: "+this);}}

getApplication()、getApplicationContext()

都是获取当前应用的上下文环境。即当前应用所使用的的Application,这在AndroidManifest中唯一指定。意味着,在当前app的任意位置使用这个函数得到的是同一个Context。

     Context applicationContext = getApplicationContext();Application application = getApplication();Log.d(TAG, "onCreate: "+applicationContext);Log.d(TAG, "onCreate: "+application);
/**打印结果:2022-10-18 23:27:52.368 20708-20708/com.example.androidlearn D/MainActivity: onCreate: android.app.Application@bad9c8a2022-10-18 23:27:52.368 20708-20708/com.example.androidlearn D/MainActivity: onCreate: android.app.Application@bad9c8a
*/

既然这两个方法得到的结果都是相同的,那么Android为什么要提供两个功能重复的方法呢?实际上这两个方法在作用域上有比较大的区别。getApplication()方法的语义性非常强,一看就知道是用来获取Application实例的,但是这个方法只有在Activity和Service中才能调用的到。那么也许在绝大多数情况下我们都是在Activity或者Service中使用Application的,但是如果在一些其它的场景,比如BroadcastReceiver中也想获得Application的实例,这时就可以借助getApplicationContext()方法了

public class MyReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {Application mApp = (Application) context.getApplicationContext();Log.d("TAG", "App is " + mApp);}}

也就是说,getApplicationContext()方法的作用域会更广一些,任何一个Context的实例,只要调用getApplicationContext()方法都可以拿到我们的Application对象。

getBaseContext()

getBaseContext()方法得到的是一个ContextImpl对象。这个ContextImpl是不是感觉有点似曾相识?回去看一下Context的继承结构图吧,ContextImpl正是上下文功能的实现类。也就是说像Application、Activity这样的类其实并不会去具体实现Context的功能,而仅仅是做了一层接口封装而已,Context的具体功能都是由ContextImpl类去完成的。那么这样的设计到底是怎么实现的呢?我们还是来看一下源码吧。因为Application、Activity、Service都是直接或间接继承自ContextWrapper的,我们就直接看ContextWrapper的源码,如下所示:

/*** Proxying implementation of Context that simply delegates all of its calls to* another Context.  Can be subclassed to modify behavior without changing* the original Context.*/
public class ContextWrapper extends Context {Context mBase;/*** Set the base context for this ContextWrapper.  All calls will then be* delegated to the base context.  Throws* IllegalStateException if a base context has already been set.* * @param base The new base context for this wrapper.*/protected void attachBaseContext(Context base) {if (mBase != null) {throw new IllegalStateException("Base context already set");}mBase = base;}/*** @return the base context as set by the constructor or setBaseContext*/public Context getBaseContext() {return mBase;}@Overridepublic AssetManager getAssets() {return mBase.getAssets();}@Overridepublic Resources getResources() {return mBase.getResources();}@Overridepublic ContentResolver getContentResolver() {return mBase.getContentResolver();}@Overridepublic Looper getMainLooper() {return mBase.getMainLooper();}@Overridepublic Context getApplicationContext() {return mBase.getApplicationContext();}@Overridepublic String getPackageName() {return mBase.getPackageName();}@Overridepublic void startActivity(Intent intent) {mBase.startActivity(intent);}@Overridepublic void sendBroadcast(Intent intent) {mBase.sendBroadcast(intent);}@Overridepublic Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {return mBase.registerReceiver(receiver, filter);}@Overridepublic void unregisterReceiver(BroadcastReceiver receiver) {mBase.unregisterReceiver(receiver);}@Overridepublic ComponentName startService(Intent service) {return mBase.startService(service);}@Overridepublic boolean stopService(Intent name) {return mBase.stopService(name);}@Overridepublic boolean bindService(Intent service, ServiceConnection conn,int flags) {return mBase.bindService(service, conn, flags);}@Overridepublic void unbindService(ServiceConnection conn) {mBase.unbindService(conn);}@Overridepublic Object getSystemService(String name) {return mBase.getSystemService(name);}......
}

由于ContextWrapper中的方法还是非常多的,我就进行了一些筛选,只贴出来了部分方法。那么上面的这些方法相信大家都是非常熟悉的,getResources()、getPackageName()、getSystemService()等等都是我们经常要用到的方法。那么所有这些方法的实现又是什么样的呢?其实所有ContextWrapper中方法的实现都非常统一,就是调用了mBase对象中对应当前方法名的方法。

那么这个mBase对象又是什么呢?我们来看第16行的attachBaseContext()方法,这个方法中传入了一个base参数,并把这个参数赋值给了mBase对象。而attachBaseContext()方法其实是由系统来调用的,它会把ContextImpl对象作为参数传递到attachBaseContext()方法当中,从而赋值给mBase对象,之后ContextWrapper中的所有方法其实都是通过这种委托的机制交由ContextImpl去具体实现的,所以说ContextImpl是上下文功能的实现类是非常准确的。

那么另外再看一下我们刚刚打印的getBaseContext()方法,在第26行。这个方法只有一行代码,就是返回了mBase对象而已,而mBase对象其实就是ContextImpl对象,因此刚才的打印结果也得到了印证。

参考链接:Android Context完全解析

Android Context解析以及getContext()、getApplication()、getApplicationContext()和getBaseContext()区别相关推荐

  1. Android 中this、getContext()、getApplicationContext()、getApplication()、getBaseContext() 之间的区别...

    : 知之为知之,不知为不知是知也! 使用this, 说明当前类是context的子类,一般是activity application等; this:代表当前,在Activity当中就是代表当前的Act ...

  2. Android全面解析之Context机制

    文章已授权『郭霖』公众号发布 前言 很高兴遇见你~ 欢迎阅读我的文章. 在文章Android全面解析之由浅及深Handler消息机制中讨论到,Handler可以: 避免我们自己去手动写 死循环和输入阻 ...

  3. Android Context完全解析,你所不知道的Context的各种细节

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/47028975 前几篇文章,我也是费劲心思写了一个ListView系列的三部曲,虽然 ...

  4. android Context的使用

    今天,简单讲讲android中context的使用. 在Android中,Context到底是个什么鬼东西,它到底是干嘛使得,我读了很多篇文档,然而并不能清除的理解它的含义. 答案: 简单来说,就像它 ...

  5. 【42】android Context深度剖析

    android程序和java程序的区别 Android程序不像Java程序一样,随便创建一个类,写个main()方法就能跑了,而是要有一个完整的Android工程环境,在这个环境下,我们有像Activ ...

  6. Android Context 是什么?

    [转载请注明出处:http://blog.csdn.net/feiduclear_up CSDN 废墟的树] PS:修该了一些有误区的地方. 引言 Context对于Android开发人员来说并不陌生 ...

  7. Android XML解析器– XMLPullParser

    Welcome to android xml parser example using XMLPullParser. We will have a sample XML file that we wi ...

  8. android XMl 解析神奇xstream 六: 把集合list 转化为 XML文档

    前言:对xstream不理解的请看: android XMl 解析神奇xstream 一: 解析android项目中 asset 文件夹 下的 aa.xml 文件 android XMl 解析神奇xs ...

  9. android XMl 解析神奇xstream 五: 把复杂对象转换成 xml ,并写入SD卡中的xml文件

    前言:对xstream不理解的请看: android XMl 解析神奇xstream 一: 解析android项目中 asset 文件夹 下的 aa.xml 文件 android XMl 解析神奇xs ...

最新文章

  1. 构造 HDOJ 5400 Arithmetic Sequence
  2. springmvc 音频流输出_音频管理模块AudioDeviceModule解读
  3. CSS3中的transform变形
  4. Cpp 对象模型探索 / new 运算符内部调用过程分析
  5. SpringBoot中@PropertySource和@ImportResource以及@Bean
  6. 系统带你学习 WebAPIs 第四讲
  7. 【渝粤题库】陕西师范大学500013 物理教学论 作业(专升本)
  8. python点线图_Python | 点线图
  9. Uploadify 配置错误信息提示
  10. 选中一行的快捷键_常用文字编辑快捷键,学会之后,天天可以提前下班
  11. GISAXS和GIWAXS的分析
  12. 【Quant】80+面试,5个offer,Quant大神总结分享各家quant面试题
  13. 工信部:将于近期发放5G商用牌照
  14. 机器学习 扬帆起航004-02评估假设与比较检验
  15. 汉王手写芯片的触摸屏控制器应用设计
  16. Qt tableWidget导入\导出Excel表格
  17. 基于SSM架构的美发店会员信息管理系统
  18. matlab磁铁模拟,用matlab 模拟环形磁铁的磁场分布
  19. 埃夫特机器人回零偏差太大_埃夫特指令
  20. npm和cnpm的区别和安装

热门文章

  1. 悲观锁、乐观锁以及分布式锁
  2. 【图解算法】排序算法——快速排序
  3. AD常用DRC规则简单介绍
  4. python opencv 直方图均衡_深入理解OpenCV+Python直方图均衡化
  5. Linux - #!/bin/bash 和 #!/usr/bin/env bash 的区别
  6. 前端开发规范和开发文档的书写规范
  7. Electron主进程渲染进程间通信的四种方式
  8. R语言[]和[[]]操作的区别
  9. 修改QQ默认下载目录
  10. 字符数组的初始化及字符串的使用