当前位置: 首页 > news >正文

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{@OverridepublicvoidonReceive(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;@Overrideprotected 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中使用非静态内部类,因为非静态内部类会隐式持有外部类实例的引用;如果需要使用静态内部类,应该将外部实例使用作为弱引用持有。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Oracle-深入了解cache buffer chain
  • Postman常见问题及解决方法
  • 目标检测-One Stage-SSD
  • go mod 命令详解
  • C# 如何读取Excel文件
  • Qt高质量的开源项目合集
  • 0-1 knappack(0-1背包问题)
  • Go 正则匹配之跨行匹配
  • 3D换肤在服装行业的应用
  • 基于metersphere和supper-jacoco 测试覆盖率落地实践
  • 中科亿海微UART协议
  • 【PTA-C语言】实验七-函数与指针I
  • 一文初识Linux进程(超详细!)
  • 3D动态路障生成
  • 计算字符串的长度几种方法 | 递归 | 指针减指针 | 计数器 | C语言 | 详解 | 期末考试必看!!!
  • 「前端早读君006」移动开发必备:那些玩转H5的小技巧
  • Effective Java 笔记(一)
  • extract-text-webpack-plugin用法
  • Java 9 被无情抛弃,Java 8 直接升级到 Java 10!!
  • jquery ajax学习笔记
  • Laravel Telescope:优雅的应用调试工具
  • Mac 鼠须管 Rime 输入法 安装五笔输入法 教程
  • mockjs让前端开发独立于后端
  • 复习Javascript专题(四):js中的深浅拷贝
  • 给新手的新浪微博 SDK 集成教程【一】
  • 体验javascript之美-第五课 匿名函数自执行和闭包是一回事儿吗?
  • 听说你叫Java(二)–Servlet请求
  • 用Python写一份独特的元宵节祝福
  • 云大使推广中的常见热门问题
  • Redis4.x新特性 -- 萌萌的MEMORY DOCTOR
  • ​LeetCode解法汇总2808. 使循环数组所有元素相等的最少秒数
  • ​软考-高级-信息系统项目管理师教程 第四版【第23章-组织通用管理-思维导图】​
  • # Panda3d 碰撞检测系统介绍
  • # 计算机视觉入门
  • #!/usr/bin/python与#!/usr/bin/env python的区别
  • #Js篇:单线程模式同步任务异步任务任务队列事件循环setTimeout() setInterval()
  • #VERDI# 关于如何查看FSM状态机的方法
  • (Matlab)遗传算法优化的BP神经网络实现回归预测
  • (solr系列:一)使用tomcat部署solr服务
  • (翻译)Quartz官方教程——第一课:Quartz入门
  • (附源码)springboot工单管理系统 毕业设计 964158
  • (附源码)ssm考试题库管理系统 毕业设计 069043
  • (三)c52学习之旅-点亮LED灯
  • (转)人的集合论——移山之道
  • (转载)深入super,看Python如何解决钻石继承难题
  • (轉貼) VS2005 快捷键 (初級) (.NET) (Visual Studio)
  • (轉貼) 資訊相關科系畢業的學生,未來會是什麼樣子?(Misc)
  • .mp4格式的视频为何不能通过video标签在chrome浏览器中播放?
  • .NET/C# 阻止屏幕关闭,阻止系统进入睡眠状态
  • .NET4.0并行计算技术基础(1)
  • .NET简谈互操作(五:基础知识之Dynamic平台调用)
  • [ Python ]使用Charles对Python程序发出的Get与Post请求抓包-解决Python程序报错问题
  • [ vulhub漏洞复现篇 ] struts2远程代码执行漏洞 S2-005 (CVE-2010-1870)
  • [ACL2022] Text Smoothing: 一种在文本分类任务上的数据增强方法
  • [ajaxupload] - 上传文件同时附件参数值