使用FragmentStatePagerAdapter时发现的内存泄露问题
这篇文章想说的并非是由于使用 FragmentStatePagerAdapter 而导致的内存泄漏,内存泄漏的真正原因和 FragmentStaePagerAdapter 并无直接关联,但是使用 FragemntStatePagerAdapter 能让你更加直观的发现内存泄漏。
我先说说我之前遇到的问题。我们都知道,当使用 FragmentSataePagerAdapter 的时候,超出缓存范围的 Fragment 会被 FragmentManager 给 remove 掉,也就是会被销毁实例,所以FragmentSatatePagerAdapter 很适合用来处理多 Fragment 页面的状况。但我遇到的情况是,当我的 Fragment 超出缓存范围时,确实被销毁了,但是它所持有的内存却并未得到释放,也就是说它内部的数据等等并未销毁和回收。如果是页面很多的情况下,很容易就会造成程序的卡顿甚至 OOM。
一般来说,造成内存泄漏的最大可能就是某处持有该对象的引用,导致该对象无法释放内存。经排查,我在使用 ViewPager 时,创建了一个 Fragment 的 List ,用来管理所有要添加到 ViewPager 中的 Fragment ,这里的 List 可能强引用了所有的Fragment,所以造成了内存泄漏 。代码如下:
private List<Fragment> fragmentList = new ArrayList<>(); //创建List,用来管理所有要添加到ViewPager的Fragment
//添加Fragment
private void setUpFragments() {
fragmentList.clear();
fragmentList.add(new SampleListFragment());
fragmentList.add(new SamplePagerFragment());
fragmentList.add(new BlankFragment());
} viewPager.setAdapter(new FragmentStatePagerAdapter(getSupportFragmentManager()) {
@Override
public Fragment getItem(int position) {
return fragmentList.get(position); //从Fragment队列中得到Fragment并加入到ViewPager中
} @Override
public int getCount() {
return fragmentNames.size();
}
});
那么如何来验证是不是这里的原因造成内存泄漏呢?想要证明,首先就不能够在使用 List 来管理 Fragment对象了。ViewPager最麻烦的是你不能自己使用 FragmentManager 的transaction 来添加 Fragment ,因为这些操作是在 ViewPager 的内部去完成的。最后我考虑使用 List 来管理Fragment的CLASS 类,然后再通过反射的方式,创建出 Fragment 对象。这样 Fragment 对象就不会被 List 持有引用了。具体代码如下:
private List<Class> fragmentNames; //创建List来管理 Fragment的 Class //添加Fragment的Class到List中
private void setUpFragments() {
if(fragmentNames == null){
fragmentNames = new ArrayList<>();
}
fragmentNames.clear();
fragmentNames.add(SampleListFragment.class);
fragmentNames.add(SampleListFragment.class);
fragmentNames.add(SampleListFragment.class);
fragmentNames.add(SampleListFragment.class);
} viewPager.setAdapter(new FragmentStatePagerAdapter(getSupportFragmentManager()) {
@Override
public Fragment getItem(int position) {
try {
return (Fragment) fragmentNames.get(position).newInstance(); //反射加载Fragment
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
} @Override
public int getCount() {
return fragmentNames.size();
}
});
如果不会反射的同学可以看一下我前面写的介绍反射的简单使用的文章。
现在再来检查程序的内存状况,你就会发现内存能够正确的被释放,内存泄漏的问题也就解决了。
其实我以前使用 ViewPager + Fragment 的时候也并没有注意到内存泄漏的问题,直到使用了FragmentStatePagerAdapter 时才发现原来的写法可能会造成内存泄漏。当然,程序中还会有很多地方稍不注意就会导致内存泄漏的问题,我们平时写代码时应该多多考虑内存泄漏的问题,并对此进行优化。
使用FragmentStatePagerAdapter时发现的内存泄露问题的更多相关文章
- 使用ViwePager显示图片时如何防止内存泄露。
内存泄露的检测. 1. 在Android Studio中运行你的应用,然后切换到输出窗口的Android tab. 2. 尽情的玩耍你的应用,最好各个功能都用到,如果是Viewpager,则多滑动一些 ...
- Delphi结构中使用String时遇到的内存泄露问题(没有利用String的引用计数自动销毁字符串的功能)
先定义一个结构: TUserInfo = record UserID: Integer; // 用户编号 UserName: string; // 用户名end; 然后编写如下代码: proced ...
- javascript js 内存泄露工具使用
javascript内存泄露工具使用 原文:http://lanhy2000.blog.163.com/blog/static/43678608201121472644851/ 2011-03-14 ...
- FastMM内存泄露
转自:http://www.2ccc.com/article.asp?articleid=4879FastMM是非常优秀的内存管理器,但是从FastMM4Options.inc中找到合适自已程序的选项 ...
- 【翻译】JavaScript内存泄露
原文地址:http://javascript.info/tutorial/memory-leaks#tools 我们在进行JavaScript开发时,很少会考虑内存的管理.JavaScript中变量的 ...
- Visual Studio内存泄露检測工具
使用简单介绍 在敲代码的过程中.难免会遇到内存泄露的时候.这个时候假设手工查找内存泄露,不说方法没有通用的,就是真的要自己手工查找也是非常耗时间和精力的.诚然.我们能够借助一些工具,并且我们还 ...
- LeakCanary: 让内存泄露无所遁形
LeakCanary: 让内存泄露无所遁形 09 May 2015 本文为LeakCanary: Detect all memory leaks!的翻译.原文在: https://corner.squ ...
- go内存泄露case
用go写了一个守护进程程序:用于检測redis的存活状态并将结果写到zookeeper中,部署到redis机器上.对于每一个redis实例会有一个goroutine每隔固定时间去检測其状态,由主gor ...
- dotnet 6 在 Win7 系统证书链错误导致 HttpWebRequest 内存泄露
本文记录我将应用迁移到 dotnet 6 之后,在 Win7 系统上,因为使用 HttpWebRequest 访问一个本地服务,此本地服务开启 https 且证书链在此 Win7 系统上错误,导致应用 ...
随机推荐
- Vue 集成easyUI
原 Vue 集成easyUI https://blog.csdn.net/m0_37948170/article/details/84960320 参考vue官网用cli创建了Vue项目之后: n ...
- 一种新的python局部调试手法
我们都知道,python里面可以用pdb来调试代码.但是pdb往往不大好用.有时候调试代码往往在多重条件里面,直接用pdb需要下条件断点,设定复杂的条件. 一个简单的办法就是这么干. __import ...
- AssetBundle打包依赖(宽宽又欠我一顿烧烤)
using UnityEngine; using System.Collections; using UnityEditor; public class dabao : EditorWindow { ...
- STM32CubeIDE 编译C/C++程序
文章转自 https://www.cnblogs.com/skyofbitbit/p/3708216.html STM32CubeIDE 其实就是STM32CubeMx + eclipse 首先,W ...
- Docker基础——从入门到精通
一个完整的docker由几个部分组成? docker client docker daemon docker images docker containers 容器是一个存储.运输工具,它能对容器内 ...
- WAFの基本防护透明流模式v1.0
一.WAFの透明流模式 1)首先先配置WAF的网络,配置一个网桥接口,设置IP便于带内管理. 2)当然,如果需要不同网段之间都能够管 ...
- eshop1-大型电商架构演进
1. 项目初期 2. 服务器分离 以上的服务分离架构,即使文件服务crash 了,但是application server 和 Database Server 继续可以访问运行 3. 基于并发访问越来 ...
- DOM:通过文本框向下拉列表中添加内容
<!DOCTYPE html><html> <head> <meta charset="UTF-8"> ...
- php phar反序列化任意执行代码
2018年 原理一.关于流包装stream wrapper大多数的文件操作允许使用各种URL协议去访问文件路径,如data://,zlib://,php://例如常见的有include('php:// ...
- uniapp属性插值报错Interpolation inside attributes has been removed. Use v-bind or the colon shorthand instead.
解决方法: 因为vue 2.x不支持对属性使用插值{{}}的方式赋值,所以要使用v-bind指令(或简写“:”)来指定属性. v-bind指令 v-bind:id="item.id" ...