Android 理解Context

news2024/11/27 10:35:58

文章目录

  • Android 理解Context
    • Context是什么
      • Activity能直接new吗?
    • Context结构和源码
    • 一个程序有几个Context
    • Context的作用
    • Context作用域
    • 获取Context
    • getApplication()和getApplicationContext()区别
    • Context引起的内存泄露
      • 错误的单例模式
      • View持有Activity应用
      • 正确使用Context

Android 理解Context

Context是什么

Context可以理解为“上下文”或”环境“,它提供了访问系统服务及系统资源的功能,Context 参与加载资源、启动Activity、启动Service、获取系统服务/应用资源、创建View、数据库等操作。

通俗来讲:一个Android应用程序可以理解为一个部电影,Activity、Service、BroadcastReceiver、ContentProvider四大组件可以理解为电影中的四个主演。他们是由剧组(Android系统)一开始就制定好的,整部戏都是围绕这四位主演的,所以这四位主演不能随便在街上拉个人(new一个对象)就能演的,有了演员就需要摄像机拍摄,他们通过镜头(Context)将戏传递给观众,也就是说四大组件必须要在Context环境下运行,而其他的如Button、TextView、LinearLayout这些控件可以理解为配角,没有那么重要(可以new一个对象),

Activity能直接new吗?

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

Context结构和源码

在这里插入图片描述

Context源码:

public abstract class Context {
    
    // 作用1:获取应用相关信息
    public abstract ApplicationInfo getApplicationInfo();
    public abstract String getPackageName();
    public abstract Looper getMainLooper();
    public abstract int checkPermission(@NonNull String permission, int pid, int uid);

    // 作用2:获取系统/应用资源
    // 如 AssetManager、PackageManager、Resources、System Service 以及 color、string、drawable 等
    public abstract AssetManager getAssets();
    public abstract Resources getResources();
    public abstract PackageManager getPackageManager();
    public abstract Context getApplicationContext();
    public abstract ClassLoader getClassLoader();
    public final @Nullable <T> T getSystemService(@NonNull Class<T> serviceClass) { ... }

    public final String getString(@StringRes int resId) { ... }
    public final int getColor(@ColorRes int id) { ... }
    public final Drawable getDrawable(@DrawableRes int id) { ... }
    public abstract Resources.Theme getTheme();
    public abstract void setTheme(@StyleRes int resid);
    public final TypedArray obtainStyledAttributes(@StyleableRes int[] attrs) { ... }

    // 作用3:四大组件之间的交互
    // 如启动 Activity、Broadcast、Service,获取 ContentResolver 等
    public abstract void startActivity(@RequiresPermission Intent intent);
    public abstract void sendBroadcast(@RequiresPermission Intent intent);
    public abstract Intent registerReceiver(@Nullable BroadcastReceiver receiver,
                                            IntentFilter filter);
    public abstract void unregisterReceiver(BroadcastReceiver receiver);
    public abstract ComponentName startService(Intent service);
    public abstract boolean stopService(Intent service);
    public abstract boolean bindService(@RequiresPermission Intent service,
            @NonNull ServiceConnection conn, @BindServiceFlags int flags);
    public abstract void unbindService(@NonNull ServiceConnection conn);
    public abstract ContentResolver getContentResolver();
    
    // 作用4:文件相关
    // 如:获取缓存文件夹、删除文件、SharedPreference 相关等
    public abstract File getSharedPreferencesPath(String name);
    public abstract File getDataDir();
    public abstract boolean deleteFile(String name);
    public abstract File getExternalFilesDir(@Nullable String type);
    public abstract File getCacheDir();
    ...
    public abstract SharedPreferences getSharedPreferences(String name, @PreferencesMode int mode);
    public abstract boolean deleteSharedPreferences(String name);

    // 作用5:数据库
    // 如打开数据库、删除数据库、获取数据库路径等
    public abstract SQLiteDatabase openOrCreateDatabase(...);
    public abstract boolean deleteDatabase(String name);
    public abstract File getDatabasePath(String name);
   
    ...
}

Context是一个抽象类,提供了关于应用环境全局信息的信息,Android提供该抽象类的具体实现类,可以通过它获取应用程序的资源和启动Activity、发送广播等。

Context有两个实现子类:ContextImpl类和ContextWrapper类。

ContextWrapper类,如其名所言,是一个包装类,内部必须包含一个真正的Context引用,调用ContextWrapper的方法都会被指向真正的Context对。

ContextThemeWrapper类,如起名所言,内部包含了与Theme(主题)相关的信息,这里的Theme就是定义在Androidmanifest.xml中主题,只有Activity才能定义主题,Servier是不需要主题的,所以Service直接继承自ContextWrapper,Application也同理。

ContextImpl类是真正实现了Context中的所有方法,应用程序中所调用的各种Context类方法都来自该类。

总的来讲:Context是一个抽象类,有两个子类,ContextImpl是具体实现类,ContextWrapper是包装类,Activity、Service、Application虽然都继承自ContextWrapper,但是在初始化是都会创建ContextImpl对象,有ContextImpl实现Context中的方法。

一个程序有几个Context

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

为什么没有BroadcastReceiver和ContentProvider,这是因为它们都不是Context的子类,所持有的Context对象是从其他地方传过来的。

Context的作用

弹出Toast、启动Activity、启动Service、发送广播、操作数据库等。

Context作用域

Context作用域ApplicationActivityService
Show a DialogNoYesNo
Start an Activity不推荐Yes不推荐
Layout Inflation不推荐Yes不推荐
Start a ServiceYesYesYes
Send a BroadcastYesYesYes
Register Broadcast ReceiverYesYesYes
Load Resource ValuesYesYesYes

启动Activity、弹出Dialog,必须使用Activity类型的Context。这是因为Android系统出于安全考虑,不允许Activity或Dialog凭空出现,一个Activity的启动必须建立在另一个Activity的基础上,也就是Activity任务栈。

启动Activity也可以使用Application的Context,但是需要将启动模式改为singleTask。

加载布局推荐使用Activity的Context,Application和Service当然也是合法的,但是会使用系统默认的主题样式。

总而言之,Activity的Context作用域最广,这是因为Activity继承自ContextThemeWrapper,ContextThemeWrapper在ContextWrapper的基础上做了一些扩展,而Appliaction和Service继承自ContextWrapper。凡是和UI相关的都应该使用Activity的Context。

获取Context

获取Context对象的四种方法:

View#getContext():通过View获取Context对象,也就是Activity对象。

Activity#getApplicationContext():获取Application的Context。

ContextWrapper#getBaseContext():获取ContextWrapper进行装饰前的Context。

Activity#this:获取Activity对象。

getApplication()和getApplicationContext()区别

其实都是同一个对象,但是作用域不同。

getApplication()表示获取一个Application,而Application本身就是一个Context,可以在Activity、Service中使用

getApplicationContext()表示获取一个Application的Context,可以在BroadcastReceiver中使用

比如可以通过BroadcastReiver中的Context获取Application对象。

public class MyReceiver extends BroadcastReceiver{

    @Override
    publicvoidonReceive(Contextcontext,Intentintent){
        Application myApp = (Application)context.getApplicationContext();
    }
}

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的Context,会导致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);
    }
}

mDrawable对象是一个静态变量会常驻内存,持有Activity的Context,即使Activity被销毁了也不会被回收,因此造成内存泄露。

正确使用Context

  • 生命周期长的对象,优先使用Application的Context。
  • UI相关的场景,推荐使用Activity的Context。
  • 尽量不要在Activity中使用非静态内部类,因为非静态内部类会隐式持有外部类实例的引用;如果需要使用静态内部类,应该将外部实例使用作为弱引用持有。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1342480.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

OpenCV-Python(29):图像特征

目录 目标 背景介绍 常用特征 应用场景 目标 理解什么是图像特征 为什么图像特征很重要 为什么角点很重要 背景介绍 相信大多数人都玩过拼图游戏吧。首先你们拿到一张图片的一堆碎片&#xff0c;你要做的就是把这些碎片以正确的方式排列起来从而重建这幅图像。问题是&…

模拟电路基础知识笔记,你想知道的都有,建议收藏!

大家总说模电知识总是学不会&#xff0c;IC修真院为大家整理了模拟电子基础知识&#xff0c;看看你掌握了多少&#xff0c;文末可以获取全部哦。 文末可领全部文档 1、PN结是晶体二极管的基本结构&#xff0c;也是一般半导体器件的核心。 2、 射极输出器没有电压放大能力&am…

SD NAND 异常上下电测试

SD NAND 异常上下电测试的作用 SD NAND 异常上下电测试是一项关键的测试步骤&#xff0c;对确保SD NAND在不同电源条件下的稳定性和可靠性至关重要。 通过模拟正常和异常电源情况&#xff0c;测试可以验证设备的电源管理功能、检测潜在错误和异常行为&#xff0c;并评估设备在…

怎么快速去除图片水印?这些快速去除的工具赶紧码住

在数字时代的大潮中&#xff0c;图片与视频中的水印如同微小的瑕疵&#xff0c;虽然旨在维护原创者的权益&#xff0c;却往往损害了内容的观感&#xff0c;降低了他人的分享欲望。那些恼人的水印&#xff0c;常常让人们束手无策。但别担心&#xff0c;接下来我将为你揭秘几种快…

数字化时代背景下服装表演创新研究

服装表演是一门独具魅力的艺术,它既高于生活,又来源于生活。这一艺术形式通过舞台上的服装、音乐、舞蹈和表演艺术家的表现力,将时尚与创意融为一体,向观众传递着独特的美感和情感。然而,如今,我们生活在一个飞速发展的数字化时代,这为服装表演的教育带来了前所未有的机遇和挑战…

英文建筑图纸翻译工程图纸翻译

建筑图纸是以图形和文字为语言&#xff0c;详细描绘了工程建筑、机械、设备等结构、形状、尺寸及其他要求。对于建筑图纸翻译&#xff0c;表达必须清楚准确。那么&#xff0c;如何确保英文建筑图纸翻译工程图纸翻译的准确性&#xff1f; 首先&#xff0c;我们需要深入了解建筑图…

使用 pytest 相关特性重构 appium_helloworld

一、前置说明 在 pytest 基础讲解 章节,介绍了 pytest 的特性和基本用法,现在我们可以使用 pytest 的一些机制,来重构 appium_helloworld 。 appium_helloworld 链接: 编写第一个APP自动化脚本 appium_helloworld ,将脚本跑起来 代码目录结构: pytest.ini 设置: [pyt…

【C语言】程序练习(三)

大家好&#xff0c;这里是争做图书馆扫地僧的小白。非常感谢各位的支持&#xff0c;也期待着您的关注。 目前博主有着C语言、C、linux以及数据结构的专栏&#xff0c;内容正在逐步的更新。 希望对各位朋友有所帮助同时也期望可以得到各位的支持&#xff0c;有任何问题欢迎私信与…

【Leetcode 39】组合总和 —— 回溯法

39. 组合总和 给你一个无重复元素的整数数组candidates和一个目标整数target &#xff0c;找出candidates中可以使数字和为目标数target的 所有不同组合&#xff0c;并以列表形式返回。你可以按**任意顺序 **返回这些组合。 candidates中的同一个数字可以 无限制重复被选取 。…

畅捷通的 Serverless 探索实践之路

作者&#xff1a;计缘&#xff0c;阿里云云原生架构师 畅捷通介绍 畅捷通是中国领先的小微企业财税及业务云服务提供商&#xff0c;成立于 2010 年。畅捷通在 2021 年中国小微企业云财税市场份额排名第一&#xff0c;在产品前瞻性及行业全覆盖方面领跑市场&#xff0c;位居中…

百万数据集测试赛题秒级查询的MySQL方案

目录 比赛题目 最佳解法 solution_row prime_encoded 相关知识 递归 CTE SUBSTRING_INDEX 引用资料 比赛题目 有一张表 cards&#xff0c;id 是自增字段的数字主键&#xff0c;另外有4个字段 c1,c2,c3,c4 &#xff0c;每个字段随机从 1~10 之间选择一个整数&#xff…

十二:爬虫-Scrapy框架(上)

一&#xff1a;Scrapy介绍 1.Scrapy是什么&#xff1f; Scrapy 是用 Python 实现的一个为了爬取网站数据、提取结构性数据而编写的应用框架(异步爬虫框架) 通常我们可以很简单的通过 Scrapy 框架实现一个爬虫&#xff0c;抓取指定网站的内容或图片 Scrapy使用了Twisted异步网…

多平面包络的圆柱体参数估计

多平面包络的圆柱体参数估计 场景 现有多个空间平面包络一个柱体&#xff0c;从圆柱顶端俯视如图所示&#xff1a; 中心位置为圆柱实际所在位置。现在已知这些平面的参数&#xff08;每个平面的方程均为axbyczd0形式, 参数为a,b,c,d&#xff09;&#xff0c;希望求解它们包络…

阿里云oss无法访问.apk或者.ipa的文件

-- 有意栽花花不发 无心插柳柳成荫 0048-00000201 更新时间&#xff1a;2023-07-19 10:31:16 问题描述 在2023年08月15日后为Bucket开通传输加速&#xff0c;如果通过OSS传输加速域名访问其中后缀为.apk或者.ipa的文件&#xff0c;服务器返回400错误。 问题原因 出于安全…

分布式IO在工业自动化中的应用

传统的自动化产线及物流系统主要是利用PLC来处理数据&#xff0c;并将这些数据保存在PC当中。但是随着互联网技术的迅速发展&#xff0c;越来越多的系统集成商利用分布式IO模块&#xff0c;实现从控制器到自动化最底层之间的IO通信。 分布式IO在工业自动化中的应用 分布式IO是用…

再次被gpt震撼到了,md转json

1.md内容来自excel 参考链接&#xff1a; https://chat.xutongbao.top/

什么是计算机视觉

计算机视觉&#xff08;Computer Vision&#xff09;是一门研究如何让计算机能够理解和分析数字图像或视频的学科。简单来说&#xff0c;计算机视觉的目标是让计算机能够像人类一样对视觉信息进行处理和理解。为实现这个目标&#xff0c;计算机视觉结合了图像处理、机器学习、模…

低代码平台搭建ERP系统 低代码快速开发灵活的ERP

随着数字化时代的到来&#xff0c;企业迫切需要高效、灵活的ERP系统来提高运营效率。在这一背景下&#xff0c;白码低代码平台成为了企业实现数字化转型的首选工具。本文将介绍低代码开发ERP的概念&#xff0c;并以白码低代码平台为例&#xff0c;探讨其在企业数字化转型中的重…

解决jenkins、git拉取代码仓库失败Please make sure you have the correct access rights

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码&#xff1a; https://gitee.com/nbacheng/n…

spellman高压发生器电源维修XRV450PN4500 NY1059

Spellman高压电源X射线发生器维修XRV系列常见维修型号&#xff1a;XRV160N1800, XRV160N3000, XRV160P4000, XRV160P6000/208V 3o, XRV225N3000, XRV225N6000/208V 3o, XRV225P4000, XRV350PN4500, XRV450PN4500。 Spellman所拥有的变频器架构可以使高压电源获得高利用率的效率…