http://blog.sina.com.cn/s/blog_5da93c8f0102w86x.html

转至:http://blog.sina.com.cn/s/blog_5da93c8f0102w86x.html


参考:http://droidyue.com/blog/2015/04/12/avoid-memory-leaks-on-context-in-android/

什么是 Context?

简单的解释下:

(1)应用所处环境中所有信息的接口
(2)Context 只是一个抽象类,它的具体实现是由 Android 系统中的实现类提供的
(3)允许访问系统资源或类,也可以进行应用层的一些操作,例如:启动 Activity、发送广播,接收 Intent 等等……

Context 能干什么?

回顾我们使用 Context 的场景来帮助理解吧:

我们在使用自定义 View 时,使用 BaseAdapter 时,甚至是访问数据库文件时,都需要传入一个 Context 参数,大家有没有想过这到底是为什么呢?因为我们初始化自定义 View 需要将 View 与某个页面布局关联,因为我们使用 BaseAdapter 时需要某个布局文件作为子 Item,因为我们需要访问应用的数据库文件。此时 Context 就像一个系统信息管理员,你告诉它我想要访问系统的布局资源文件,想要访问应用的数据库文件,它就去给你找,然后提供引用给你使用。

所以大家现在应该能理解了吧,Context 就是用于获得系统资源的,我们所说的系统资源包括设备本身的信息,也有我们开发者提供的信息(类、包、资源文件等等……)。

Application 类和 Activity、Service 两大 Android 组件都是 Context 的具体实现类,而这三个类确实能访问各自职责内的系统资源,例如 Activity 能访问与界面元素相关的资源、Service 能访问系统服务、Application 能访问应用包名等信息。

知识点:应用中 Context 的数量 = Activity 的数量 + Service 的数量 + 1(Application 的数量)

使用 Context 你不知道的事?

前面已经提到,Context 的实现类能够持有各种各样的系统信息,可能有人会想到:使用 Context 不会导致内存泄漏吗?我在这里给大家答案:会!而且我们在开发中经常无意地导致了内存泄漏。有人可能就不服了,我写的代码怎么可能有内存泄漏的问题!

别急,我下面给大家看一段最普通的代码:

例如我们要实现一个 ListView 展示信息的功能,为了自定义子 Item,我们需要传入 Context 来读取布局资源:
public class MyBaseAdapter extends BaseAdapter{
private Context mContext;

public MyBaseAdapter(Context context) {
mContext = context;
}

省略……
}

设计完 BaseAdapter 以后,我们肯定要在 MainActivity 里面使用它了:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

adapter = new MyBaseAdapter(this);

……省略
}

一般大家都会写下这样的代码对吧?这样写都不会出现 Bug 对吧?老板还夸你工作效率高对吧?事实上这样的代码会导致内存泄漏哦~为什么呢?大家不妨回顾我在在Activity中使用Thread导致的内存泄漏里提到的内存泄漏原因,博文中说道:只要类持有对外部类实例对象的引用,垃圾回收机制就不会回收该对象。

在这段代码中,我们将 Activity 的引用传入 MyBaseAdapter,使得 MyBaseAdapter 持有对 Activity 的引用,那么相应地,我们也将持有 Activity 所获得的资源文件的引用。所以这些资源文件将无法被垃圾回收机制回收,造成内存泄漏的问题。

那么有什么解决办法呢?

我们只需要修改一句代码:
mContext = context.getApplicationContext();
或者
adapter = new MyBaseAdapter(this.getApplication());
就可以避免内存泄漏的问题。大家需要记住的是,在这里我们只是演示了一种最常见,最基础的 Context 导致的内存泄漏问题,在实际的开发需求中肯定还有更加复杂的情况,大家应该更多地去思考背后的原因,从根源上解决这些内存泄漏的问题。

常见Context内存泄漏情况

这是一个很隐晦的OutOfMemoryError的情况。先看一个Android官网提供的例子:
Java代码
private static Drawable sBackground;
@Override
protected void onCreate(Bundle state) {
super.onCreate(state);

TextView label = new TextView(this);
label.setText("Leaks are bad");

if (sBackground == null) {
sBackground = getDrawable(R.drawable.large_bitmap);
}
label.setBackgroundDrawable(sBackground);

setContentView(label);
}

这段代码效率很快,但同时又是极其错误的;
在第一次屏幕方向切换时它泄露了一开始创建的Activity。当一个Drawable附加到一个 View上时,
View会将其作为一个callback设定到Drawable上。上述的代码片段,意味着Drawable拥有一个TextView的引用,
而TextView又拥有Activity(Context类型)的引用,换句话说,Drawable拥有了更多的对象引用。即使Activity被 销毁,内存仍然不会被释放。
另外,对Context的引用超过它本身的生命周期,也会导致Context泄漏。所以尽量使用Application这种Context类型。
这种Context拥有和应用程序一样长的生命周期,并且不依赖Activity的生命周期。如果你打算保存一个长时间的对象,
并且其需要一个 Context,记得使用Application对象。你可以通过调用Context.getApplicationContext()或 Activity.getApplication()轻松得到Application对象。
最近遇到一种情况引起了Context泄漏,就是在Activity销毁时,里面有其他线程没有停。
总结一下避免Context泄漏应该注意的问题:
1.使用Application这种Context类型。
2.注意对Context的引用不要超过它本身的生命周期。
3.慎重的使用“static”关键字。
4.Context里如果有线程,一定要在onDestroy()里及时停掉。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
W: http://archive.ubuntu.com/ubuntu/dists/jammy/InRelease: The key(s) in the keyring /etc/apt/trusted.gpg.d/ubuntu-keyring-2012-cdimage.gpg are ignored as the file is not readable by user '_apt' executing apt-key. W: http://archive.ubuntu.com/ubuntu/dists/jammy/InRelease: The key(s) in the keyring /etc/apt/trusted.gpg.d/ubuntu-keyring-2018-archive.gpg are ignored as the file is not readable by user '_apt' executing apt-key. W: GPG error: http://archive.ubuntu.com/ubuntu jammy InRelease: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 871920D1991BC93C E: The repository 'http://archive.ubuntu.com/ubuntu jammy InRelease' is not signed. W: http://security.ubuntu.com/ubuntu/dists/jammy-security/InRelease: The key(s) in the keyring /etc/apt/trusted.gpg.d/ubuntu-keyring-2012-cdimage.gpg are ignored as the file is not readable by user '_apt' executing apt-key. W: http://security.ubuntu.com/ubuntu/dists/jammy-security/InRelease: The key(s) in the keyring /etc/apt/trusted.gpg.d/ubuntu-keyring-2018-archive.gpg are ignored as the file is not readable by user '_apt' executing apt-key. W: GPG error: http://security.ubuntu.com/ubuntu jammy-security InRelease: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 871920D1991BC93C E: The repository 'http://security.ubuntu.com/ubuntu jammy-security InRelease' is not signed. W: http://archive.ubuntu.com/ubuntu/dists/jammy-updates/InRelease: The key(s) in the keyring /etc/apt/trusted.gpg.d/ubuntu-keyring-2012-cdimage.gpg are ignored as the file is not readable by user '_apt' executing apt-key. W: http://archive.ubuntu.com/ubuntu/dists/jammy-updates/InRelease: The key(s) in the keyring /etc/apt/trusted.gpg.d/ubuntu-keyring-2018-archive.gpg are ignored as the file is not readable by user '_apt' executing apt-key. W: GPG error: http://archive.ubuntu.com/ubuntu jammy-updates InRelease: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 871920D1991BC93C E: The repository 'http://archive.ubuntu.com/ubuntu jammy-updates InRelease' is not signed. W: http://archive.ubuntu.com/ubuntu/dists/jammy-backports/InRelease: The key(s) in the keyring /etc/apt/trusted.gpg.d/ubuntu-keyring-2012-cdimage.gpg are ignored as the file is not readable by user '_apt' executing apt-key. W: http://archive.ubuntu.com/ubuntu/dists/jammy-backports/InRelease: The key(s) in the keyring /etc/apt/trusted.gpg.d/ubuntu-keyring-2018-archive.gpg are ignored as the file is not readable by user '_apt' executing apt-key. W: GPG error: http://archive.ubuntu.com/ubuntu jammy-backports InRelease: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 871920D1991BC93C E: The repository 'http://archive.ubuntu.com/ubuntu jammy-backports InRelease' is not signed. E: Problem executing scripts APT::Update::Post-Invoke 'rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true' E: Sub-process returned an error code
最新发布
06-07

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值