Android 理解Context

文章目录

  • 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.mfbz.cn/a/279864.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

安全配置审计概念、应用场景、常用基线及扫描工具

软件安装完成后都会有默认的配置&#xff0c;但默认配置仅保证了服务正常运行&#xff0c;却很少考虑到安全防护问题&#xff0c;攻击者往往利用这些默认配置产生的脆弱点发起攻击。虽然安全人员已经意识到正确配置软件的重要性&#xff0c;但面对复杂的业务系统和网络结构、网…

儿童学python语言能做什么,儿童学python哪个机构好

这篇文章主要介绍了儿童学python哪个线上机构好&#xff0c;具有一定借鉴价值&#xff0c;需要的朋友可以参考下。希望大家阅读完这篇文章后大有收获&#xff0c;下面让小编带着大家一起了解一下。 少儿编程python 文章目录 前言 CSP-J与CSP-S少儿编程证书含金量排名&#xff0…

SSH -L:安全、便捷、无边界的网络通行证

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 SSH -L&#xff1a;安全、便捷、无边界的网络通行证 前言1. SSH -L基础概念SSH -L 的基本语法&#xff1a;端口转发的原理和作用&#xff1a; 2. SSH -L的基本用法远程访问本地示例&#xff1a;访问本…

git 常用操作合集

✨专栏介绍 在当今数字化时代&#xff0c;Web应用程序已经成为了人们生活和工作中不可或缺的一部分。而要构建出令人印象深刻且功能强大的Web应用程序&#xff0c;就需要掌握一系列前端技术。前端技术涵盖了HTML、CSS和JavaScript等核心技术&#xff0c;以及各种框架、库和工具…

贴片电容和薄膜电容的区别

一、贴片电容和薄膜电容的定义 贴片电容是指体积较小、形状像片的电容器&#xff0c;广泛应用于电路板和电子元器件中。薄膜电容是指以金属膜作为电极的电容器&#xff0c;广泛应用于高频和精密电路中。 二、贴片电容和薄膜电容的应用 贴片电容广泛应用于数码产品、无线通信…

JavaScript中实现页面跳转的几种常用方法

Hi i,m JinXiang ⭐ 前言 ⭐ 本篇文章主要介绍在JavaScript中实现页面跳转的几种常用方法以及部分理论知识 &#x1f349;欢迎点赞 &#x1f44d; 收藏 ⭐留言评论 &#x1f4dd;私信必回哟&#x1f601; &#x1f349;博主收将持续更新学习记录获&#xff0c;友友们有任何问题…

Linux文件的扩展属性 attr cap

文件属性 Linux文件属性分为常规属性与扩展属性&#xff0c;其中扩展属性有两种&#xff1a;attr与xattr. 一般常规的文件属性由stat API 读取&#xff0c;一般是三种权限&#xff0c;ower, group&#xff0c;时间等。 扩展属性attr 用户态API ioctl(fd, FS_IOC32_SETFLAGS…

git回滚操作,常用场景

文章目录 git回滚操作1.git reset --hard 【版本号】2.回滚后的版本v2又想回到之前的版本v32.1 git reflog 3.git checkout -- 文件名4.git reset HEAD 文件名 git回滚操作 假设我们现在有三个版本 现在回滚一个版本 1.git reset --hard 【版本号】 发现只剩下两个版本了 2.…

二叉树简单实现(C语言版)

一.简单建二叉树 在学习二叉树的基本操作前&#xff0c;需先要创建一棵二叉树&#xff0c;然后才能学习其相关的基本操作。由于现在大家对二 叉树结构掌握还不够深入&#xff0c;为了降低大家学习成本&#xff0c;此处手动快速创建一棵简单的二叉树&#xff0c;快速进入二叉树 …

二叉树顺序结构与堆的概念及性质(c语言实现堆)

上次介绍了树&#xff0c;二叉树的基本概念结构及性质&#xff1a;二叉树数据结构&#xff1a;深入了解二叉树的概念、特性与结构 今天带来的是&#xff1a;二叉树顺序结构与堆的概念及性质&#xff0c;还会用c语言来实现堆 文章目录 1. 二叉树的顺序结构2.堆的概念和结构3.堆…

Kafka:本地设置

这是设置 Kafka 将数据从 Elasticsearch 发布到 Kafka 主题的三部分系列的第一部分;该主题将被 Neo4j 使用。第一部分帮助您在本地设置 Kafka。第二部分将讨论如何设置Elasticsearch将数据发布到Kafka主题。最后 将详细介绍如何使用连接器订阅主题并使用数据。 Kafka Kafka 是…

SpringBoot项目部署及多环境

1、多环境 2、项目部署上线 原始前端 / 后端项目宝塔Linux容器容器平台 3、前后端联调 4、项目扩展和规划 多环境 程序员鱼皮-参考文章 本地开发&#xff1a;localhost&#xff08;127.0.0.1&#xff09; 多环境&#xff1a;指同一套项目代码在把不同的阶段需要根据实际…

守护青山绿水 千巡翼Q20无人机变身护林员

守护青山绿水 千巡翼Q20无人机变身护林员 无人机目前在林业上的应用主要在森林资源调查、森林资源监测、森林火灾监测、森林病虫害监测防治、野生动物监测等方面。传统手段在森林资源调查中需要耗费大量人力物力&#xff0c;利用无人机技术可快速获得所需区域高精度信息&#…

Java核心知识点1-java和c++区别、隐式和显示类型转换

java和c区别 java通过虚拟机实现跨平台特性&#xff0c;但c依赖于特定的平台。java没有指针&#xff0c;它的引用可以理解为安全指针&#xff0c;而c和c一样具有指针。java支持自动垃圾回收&#xff0c;而c需要手动回收。java不支持多重继承&#xff0c;只能通过实现多个接口来…

WPF 消息日志打印帮助类:HandyControl+NLog+彩色控制台打印+全局异常捕捉

文章目录 前言相关文章Nlog配置HandyControl配置简单使用显示效果文本内容 全局异常捕捉异常代码运行结果 前言 我将简单的HandyControl的消息打印系统和Nlog搭配使用&#xff0c;简化我们的代码书写 相关文章 .NET 控制台NLog 使用 WPF-UI HandyControl 控件简单实战 C#更改…

【嵌入式开发 Linux 常用命令系列 7.3 -- linux 命令行数值计算】

文章目录 linux 命令行数值计算使用 awk使用 bc 命令使用 Bash 的内置算术扩展使用 expr脚本命令实现 linux 命令行数值计算 在 Linux 命令行中&#xff0c;您可以使用多种方法来执行基本的数学运算。以下是一些示例&#xff1a; 使用 awk awk 是一个强大的文本处理工具&…

Linux第一个小程序-进度条(c语言版)

目录 行缓冲区概念&#xff1a; 行缓冲区代码演示&#xff1a; ​编辑进度条代码 1&#xff1a;memset函数&#xff1a; 2&#xff1a;const char* lable"|/-\\"; 3&#xff1a;usleep C语言 usleep 函数的功能和用法&#xff1a; 4&#xff1a;进度条代码的实…

C语言经典算法【每日一练】20

题目&#xff1a;有一个已经排好序的数组。现输入一个数&#xff0c;要求按原来的规律将它插入数组中。 1、先排序 2、插入 #include <stdio.h>// 主函数 void main() {int i,j,p,q,s,n,a[11]{127,3,6,28,54,68,87,105,162,18};//排序&#xff08;选择排序&#xff09…

12.21自动售货机,单物品,多物品

自动售货机 if朴素方法 一种思路是用寄存器cnt记录已有的最小单位货币量&#xff0c;这里就是0.5 当d1时&#xff0c;cnt1;d2时&#xff0c;cnt2;d3时&#xff0c;cnt4; timescale 1ns/1ns module seller1(input wire clk ,input wire rst ,input wire d1 ,input wire d2 …

Python:日期和时间类型学习

背景 在非开发环境经常需要做一下日期计算&#xff0c;就准备使用Python&#xff0c;顺便记下来学习的痕迹。 代码 1 1 # coding utf-82 2 3 3 from datetime import *4 4 5 5 ########################## 日期 ##########################6 6 date_now date.today()…
最新文章