本篇文章是受我影响很大的一位粉丝「MeloDev」的投稿,其实每天都有大量的粉丝找我投稿,但是本着对大家的负责,我都会认真审核,不求文章内容多么高级,但是一定是用心写,并且我自己觉得还不错的文章才会通过,因为不想把投稿的文章放在二级文章列表之后,本着每天尽量只发一篇精品文章,导致很多不错的投稿文章发布比较慢,这篇文章其实都是上周五就找我了,还请见谅!

另外这个公号全部都是我个人在维护,但是我自己本身在薄荷的工作非常之忙,能坚持下来着实不容易,现在几乎牺牲了我所有业余时间,包括我每天的午睡时间、晚上下班之后的时间以及周末的时间,我已经记不清有多久没有打过一把Dota了。

写作这种分享方式是我本身比较喜欢的,这个号我很认真的在维护,大部分都是我原创文章,投稿的文章我也会亲自审核,每个赞赏的人我都会亲自回复表达谢意,有时候如果刚好在看某些电子书或者文章之类的,觉得不错顺便就回复给赞赏支持我的人了,所有的留言我都会一一过目,我每天产生的原创文章大多都是参考留言里大家最迫切的需求,我自认为个人公号很少有我这么认真的了!

有一些在线教育邀请了我无数次去他们平台给付费用户做直播或者录课程,我一看那些付费用户的价格,真的吓到了,平均一节课45分钟要两三百块,我跟他们说为什么价格就不能放开让所有人接受呢?比如10块、20块一节课,这多么亲民,大家也能接受。我一直认为好的知识需要付费,但是这价格未免太过昂贵了!

一是没时间,二是我着实不喜欢这功利性质的分享,虽然可能我会赚的比现在多得多,但是我还是选择继续以我喜欢的方式给大家做分享。只希望大家对我多多支持,依据个人经济能力赞赏,金额随意,哪怕是一块钱,对你可能没什么,但是却是对我莫大的鼓励。留言区上方的广告也请大家坚持点击下,你们并不会损失什么,但是我却可以靠这点小钱每天多给我媳妇买点水果吃,媳妇靠我的努力每天都能有免费的水果吃想想都好开心...


写在前面

Context对象在我们的项目中实在是太常见了,启动Activity、Service、发送一个Broadcast,作为获取各种系统Resources的参数,Layout Inflation的参数,show a Dialog的参数等等。Context对象的使用不当,是可能造成内存泄漏的,当你的工程代码已经达到十几万行甚至是几十万行时,Context对象就对内存泄漏造成非常可观的影响了,所以我们应该对Context对象的使用,做到心中有数。

什么是Context

前两天刚刚对 Context 写了一篇比较长的博客,借鉴大牛们的经验,对 Context 进行了比较详细的整合与总结,花半个小时的时间耐心读一读吧!

「你足够了解 Context 吗?」

一句话总结:

Context是为一个Android程序提供各种功能、资源、服务的一个环境, Context 的资源在系统中只有一套,因为它的子类(Application、Activity、Service)对这同一块资源处理方式的不同,让Context 对象在功能上表现出各自之间的差异。

Context对象之间的差异

相信如果你是一个初学者, Context 在你手里应该是胡乱传入的,哪里有 Context 就找哪里,各种this乱入,O(∩_∩)O哈哈,至少当时我是这样的,但是 Context 不同的对象在使用功能上是有区别的,比如以下代码:

在清单文件中做以下配置:

在界面中show a Dialog

点击按钮之后崩溃信息

当我使用Application的Context时,是无法弹出一个Dialog的,因为Dialog作为一个View,依附在Activity上,并且与Theme相关,当传入参数为Actvity的Context时,崩溃就解决了。

下面这张表展示出了Context对象之间使用上的差异:

Context相关的内存泄漏问题

在讨论内存泄漏之前,先简单的说说Android中内存的回收

Dalivik虚拟机扮演了常规的垃圾回收角色,为了GC能够从App中及时回收内存,我们需要时时刻刻在适当的时机来释放引用对象,Dalvik的GC会自动把离开活动线程的对象进行回收。

什么是Android内存泄漏:

虽然Android是一个自动管理内存的开发环境,但是垃圾回收器只会移除那些已经失去引用的、不可达的对象,在十几万、几十万行代码中,由于你的失误使得一个本应该被销毁的对象仍然被错误的持有,那么该对象就永远不会被释放掉,这些已经没有任何价值的对象,仍然占据聚集在你的堆内存中,GC就会被频繁触发,多说几句,如果手机不错,一次GC的时间70毫秒,不会对应用的性能产生什么影响,但是如果一个手机的性能不是那么出色,一次GC时间120毫秒,出现大量的GC操作,我相信用户就能感觉到了吧。这些无用的引用堆积在堆内存中,越积越多最终导致Crash,有关一些性能优化推荐给大家一个我总结的博客。

「Android性能优化总结」

有些跑题了,我们赶紧来看看什么情况下Context会引发内存泄漏

  • 错误的单例模式

我们来分析一下这个非线程安全的单例模式,假设你在Activity A去getInstance获得instance对象,顺手传了一个this,好了,现在一个常驻内存的Singleton保存了你传入Activity A的对象,并且一直持有Activity A的引用,这样即使你Activity被销毁掉,但是因为它的引用还存在于一个Singleton中,是不可能被GC掉的,这样就导致了内存泄漏。

  • View持有Activity的引用

再来分析一下,有一个静态的Drawable对象,当我给ImageView设置这个Drawable时,ImageView像上面那个例子一样,保存了这个mDrawable的引用(大家可以点开源码705行去看,很多UI组件都是统一的操作,一直持有传入的对象),然而ImageView传入了this,也就是ImageView同样持有一个MainActivity的mContext。因为被static修饰的mDrawable是常驻内存的,MainActivity是它的间接引用,所以当MainActivity被销毁时,也不能被GC掉,所以也造成了内存泄漏。

使用Context的正确姿势

通俗一点说,Context造成的内存泄漏,几乎都是当Context销毁的时候,却还被各种不合理、无端地引用着。那么哪个Context对象是不会被销毁的呢?对了,Application的Context对象可以理解为随着进程存在的,所以当Application的Context能搞定的情况下,并且生命周期长的对象,优先使用Application的Context

调用一行代码:

LaucherApplication.getContext();

回头看看上面那张表格,显然Application的Context不是万能的,涉及UI加载操作时,似乎我们只能使用Activity的Context,所以你当你使用Activity的Context时,你要对持有Activity的对象心中有数,保证它能随着生命周期的销毁而被回收,慎用static关键字,不要因为方便访问就各种static乱入。

多说一点,上表中Layout Inflation中只能使用Activity的Context,而各种View在创建时,需要传入的Context参数也是Activity的,大家懂了吧,当解析XML文件的时候,传入的参数也就统一了,相信大家一定能想明白这点。

写在最后:

给大家推荐一个内存检测的自动化工具,LeakCanary,但是当你曾经写出的代码不规范不负责,已经达到十几万行,几十万行的时候,再去抽丝剥茧试图解开已经打上层层死结的引用关联,是非常难的。所以平时还是要注意下细节哈~

微信不支持外链,可以点击「阅读原文」跳转到原博客。


对了,微信最新版公众号可以「置顶」了哦,觉得我的公号很赞,不妨设置「置顶」。

你真的会用Context么?相关推荐

  1. 架构组件专栏 | ViewModel深入浅出

    本文是架构组件专栏的开篇文章,因此在文章开头我打算花些笔墨谈谈什么是架构组件以及我为什么打算写这个专栏. 谷歌官方为了帮助开发者加速开发并构建高质量的应用,推出了Jetpack.正如上图你所看到的,J ...

  2. Spring Context 你真的懂了吗?

    今天介绍一下大家常见的一个单词 context 应该怎么去理解,正确的理解它有助于我们学习 spring 以及计算机系统中的其他知识. 1. context 是什么 我们经常在编程中见到 contex ...

  3. 识别迷雾中的物体,谷歌提出最新目标检测算法Context R-CNN

    晓查 发自 凹非寺  量子位 报道 | 公众号 QbitAI 你能从下面的照片里看到什么吗? 呃,看起来像清晨的浓雾,但浓雾后面是什么,真的看不清楚.其实这是一群牛羚在山上行走. 虽然人眼已经无能为力 ...

  4. Android逆向之路---Faceu的登录功能真的只提交了用户名和密码吗

    问题 几乎99%的软件都有登录功能,而登录这一个动作真的将我们的用户名和密码上传到了服务器吗,会不会有个人隐私呢.根据我们这个问题,我们用FaceU这个软件,逆向来看看他的登录功能到底都传了什么数据. ...

  5. 云计算时代,你真的懂 Docker 吗?

    要论云计算领域中,开发者需要具备哪些基本技能?那么 Docker 必是其一. 作为一个开源的应用容器引擎,Docker 能够让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行 ...

  6. foreach判断最后一个_JavaScript很简单?那你理解的forEach真的对吗?

    你理解的Array.prototype.forEach真的对吗? Array.prototype.forEach 我们都知道,forEach() 方法对数组的每个元素执行一次给定的函数.它的语法也很简 ...

  7. update值与原值相同时,SQL Server会真的去update还是忽略呢?

    原文:update值与原值相同时,SQL Server会真的去update还是忽略呢? 考虑下面的情况: 当update值与原值相同时,SQL Server会真的去update还是忽略?例如: upd ...

  8. Python——with语句、context manager类型和contextlib库

    目录 一.with语句 二.上下文管理器 三.contextlib模块 基本概念 上下文管理协议(Context Management Protocol) 包含方法 __enter__() 和 __e ...

  9. 此上下文中不允许函数定义。_深度好文 | 你知道Go中的 context 是怎么实现的吗?...

    Go语言中文网,致力于每日分享编码知识,欢迎关注我,会有意想不到的收获! Go 语言的 context 包短小精悍,非常适合新手学习.不论是它的源码还是实际使用,都值得投入时间去学习. 这篇文章依然想 ...

  10. Android:字节跳动必备Context原理解析及使用

    Activity mActivity =new Activity() 作为Android开发者,不知道你有没有思考过这个问题,Activity可以new吗?Android的应用程序开发采用JAVA语言 ...

最新文章

  1. 英语中单词属性的简称
  2. 【MM 模块】 Optimized Purchasing 优化采购 3
  3. wpf 如何设置弹出窗口必须关闭才能打开其他软件_CAD如何打印才能不留白?原来打印图纸还有这么多技巧?...
  4. thinkphp5.0 使用paginate 分页后 foreach 循环体内不能处理数据的解决办法
  5. 25 SD配置-主数据-信用管理-定义信用段
  6. Flume-ng HDFS sink原理解析
  7. 数据库第二节 sql表格创建及内容插入和查询
  8. win10电脑忘记开机密码的解锁方法
  9. 【多目标优化算法】基于分解的多目标进化算法 MOEA/D
  10. 手机如何远程连接服务器
  11. Java url中文转码
  12. 教你设置无线wifi无缝漫游,实现无线wifi自动切换联网
  13. 登录模块 用户认证 SpringSecurity +Oauth2+Jwt
  14. 大数据导论学习日志Day1
  15. 【历史上的今天】2 月 20 日:Python 问世;Facebook 收购 WhatsApp;DEC 创始人出生
  16. android 蓝牙传输速率,android蓝牙rfcomm连接速度太慢
  17. PCB碎碎念——贴片封装与标识
  18. 三星手机大量死机!我反编译折腾半天后,发现竟然一个汉字引发的....
  19. 【Elasticsearch】利用kibana调整索引mapping结构
  20. 网站加入代码让网页以电脑端打开_发现一个超级好用的视频播放网站-酷播云...

热门文章

  1. undefined reference to `create_module''
  2. UNIX环境高级编程之第9章:进程关系
  3. 苹果 Mac 如何同时输出两个蓝牙喇叭或两副 AirPods 耳机?
  4. 已支持macOS Big Sur 的apple App更新列表
  5. Mac电脑上的Safari运行缓慢,卡的要死,该怎么解决?
  6. 【Java6学习笔记】多线程编程中使用volatile保障原子性
  7. Python自学笔记-lambda函数(来自廖雪峰的官网Python3)
  8. 常用Docker 镜像命令(二)
  9. java Http post请求发送json字符串
  10. 西安Uber优步司机奖励政策(1月11日~1月17日)