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

网站开发技术项目说明书百度推广优化工具

网站开发技术项目说明书,百度推广优化工具,做粤菜的视频网站,做电子商务系统网站建设案例3——view内存泄漏 前文提到,profile#Leaks视图无法展示非Activity、非Fragment的内存泄漏,换言之,除了Activity、Fragment的内存泄漏外,其他类的内存问题我们只能自己检索hprof文件查询了。 下面有一个极佳的view内存泄漏例子…

案例3——view内存泄漏
前文提到,profile#Leaks视图无法展示非Activity、非Fragment的内存泄漏,换言之,除了Activity、Fragment的内存泄漏外,其他类的内存问题我们只能自己检索hprof文件查询了。
下面有一个极佳的view内存泄漏例子,它的操作步骤为:

  1. 播放音乐,唤醒音乐悬浮窗
  2. 播放一段时间后,关闭音乐悬浮窗
  3. 重复步骤1和2

我们重复三次之后,得到一份hprof文件,下面我们来分析一下内存泄漏问题
在这里插入图片描述

①输入view的名称
②选择view
③可以看到分配了3个实例对象
④Instance List视图显示,view有3个实例对象及其引用
我们从上至下依次看3分实例的调用链

第一个泄漏点

view的第一个实例
先查看Fields区域,观察mLayoutmode值,判断view是否离开了窗口,如果已经离开了窗口,表明view未被回收,存在内存泄漏

在这里插入图片描述
可以看到mLayoutMode = -1 ,表明布局已经离开屏幕了,此实例存在内存泄漏的情况
在这里插入图片描述

接着我们查看References区域,逐级点开我们发现Handler发送的Message持有了当前view,导致view在离开窗口的时候,无法被垃圾回收器回收。
右键点击查看问题代码

在这里插入图片描述
问题代码:

   playHandler.post(new Runnable() {@Overridepublic void run() {tv_play.setText(playItem.getProgramTitle());tb_play.setSelected(true);initView();}});

看到new Runnbale,这是是匿名内部类,匿名内部类持有当前类的引用,匿名Runnbale未执行完毕,Runnbale内存未释放的时候,view就无法被释放,而匿名Runnbale的释放时机不可控,由Handler、Looper、Runnbale执行情况影响。
那么我们该怎么优化呢?

  1. 使用非匿名或静态的Handler+弱引用,处理此任务
  2. 在主线程处理此任务
  3. view退出的时候释放Message对view的引用
    笔者采用了方案3:
tv_play.setText(playItem.getProgramTitle());
tb_play.setSelected(true);
initView();

方案1代码与下面view的第三个实例写法一致,不重复写了;我们解释一下方案3:

view退出的时候释放Message对view的引用
根据上图所示,我们看到Message-Runnbale-View的引用关系可知,Looper中的Message持续的引用view,我们最高效释放内存的做法是view离开窗口的时候,斩断Message与view的引用关系,那么我们该怎么做呢?答案是:

  1. 结束子线程任务
  2. 清空Looper缓存的Message
  3. 释放Handler

第一步:结束子线程任务很简单
thread.interrupt()
本案例给Handler传入的是Runnbale,Handler未提供结束Runnbale的接口,此项优化搁置
第二步:清空Message
已知Looper提供了清空Message的接口

  1. Looper#quit
  2. Looper#quitSafely
  3. 主线程的Looper无法退出
    已知Handler提供了释放Message的接口
  4. Handler#removeCallbacksAndMessages
    那我们优化起来就很简单了,清空Handler持有的Message
@Override protected void onDetachedFromWindow() { 
super.onDetachedFromWindow(); ... // 释放message,断开message-Runnbale-view的引用链 if (playHandler != null) { playHandler.removeCallbacksAndMessages(null); playHandler = null; }}

第二个泄漏点

我们继续看view的第二个实例
先查看Fields区域,观察mLayoutmode值,判断view是否离开了窗口,如果已经离开了窗口,表明view未被回收,存在内存泄漏

在这里插入图片描述
可以看到mLayoutMode = -1 ,表明布局已经离开屏幕了,此实例存在内存泄漏的情况
接着我们看References区域,观察调用链
在这里插入图片描述
可以看到MediaPlayerIml有一个成员变量mMediaPlayListenerCacheList,缓存了MediaPlayListener,MediaPlayListener又是在view实例里面创建的,并且作为内部类,它持有view的实例。现在我们得到了清晰的调用链,MediaPlayerIml->mMediaPlayListenerCacheList->MediaPlayListener->view,MediaPlayerIml引用view导致view实例无法被释放
查看问题代码:
笔者发现view#onDetachedFromWindow已经触发了移除list#listener操作

@Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); mediaPlayerIml.unregisterListener(playListener); 

可以看到内部实现是remove调引用的

 /*** 取消注册listener** @param listener*/public synchronized void unregisterListener(MediaPlayListener listener) {mMediaPlayListenerCacheList.remove(listener);}

那为什么会未回收持续占用内存呢?

  1. 抓拍hprof文件期间,代码未执行到unregisterListener,导致view内存未得到释放
  2. mMediaPlayListenerCacheList添加的listener与remove的listener不是同一个
  3. 此处没有产生内存泄漏,判断view是否应该被回收的依据有问题

第三个泄漏点

搁置疑问,接着我们来看view的第三个实例,节省时间,笔者直接调到代码索引出,展示问题代码:

  /*** 播放进度条刷新控*/private Handler m_handler = new Handler() {@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);switch (msg.what) {case MSG_FLUSH_SEEKBAR:boolean isPlaying = mediaPlayerIml != null && mediaPlayerIml.getPlayStatus() == QingtingConfig.PLAY;if (isPlaying) {int currentTime = mediaPlayerIml.getCurrentTime();int totalTime = mediaPlayerIml.getTotalTime();mSeekBar.setMax(totalTime);mSeekBar.setProgress(currentTime);mPrograssBar.setMaxProgress(totalTime);mPrograssBar.setCurrentProgress(currentTime);LoggerUtils.instance().logE("mediaPlayJindu", "mediaPlayJindu" + totalTime + "/" + currentTime);}m_handler.sendEmptyMessageDelayed(MSG_FLUSH_SEEKBAR, MSG_FLUSH_TIME);break;}}};

可以看到此处还是使用了非静态内部类m_handler,m_handler持有当前view 的引用,m_handler如果长期存在,那么view的内存也不会被释放
解决方法如下:

  1. 定义外部类Handler
  2. 定义静态内部类
  3. 定义静态内部类+弱引用
    笔者采用了方案3:
    定义静态内部类
 private  static  class UpdateHandler extends Handler {private final WeakReference<MediaPlayerIml> mediaPlayerImlWeakReference;private final WeakReference<SeekBar> seekBarWeakReference;private final WeakReference<QQCircleProgressBar> progressBarWeakReference;public UpdateHandler(MediaPlayerIml mediaPlayerIml, SeekBar seekBar, QQCircleProgressBar progressBar) {mediaPlayerImlWeakReference = new WeakReference<MediaPlayerIml>(mediaPlayerIml);seekBarWeakReference = new WeakReference<SeekBar>(seekBar);progressBarWeakReference = new WeakReference<QQCircleProgressBar>(progressBar);}@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);if (msg.what == MSG_FLUSH_SEEKBAR) {MediaPlayerIml mediaPlayerIml = mediaPlayerImlWeakReference.get();SeekBar seekBar = seekBarWeakReference.get();QQCircleProgressBar qqCircleProgressBar =progressBarWeakReference.get();boolean isPlaying = mediaPlayerIml != null && mediaPlayerIml.getPlayStatus() == QingtingConfig.PLAY;if (isPlaying && seekBar!=null && qqCircleProgressBar != null) {int currentTime = mediaPlayerIml.getCurrentTime();int totalTime = mediaPlayerIml.getTotalTime();seekBar.setMax(totalTime);seekBar.setProgress(currentTime);qqCircleProgressBar.setMaxProgress(totalTime);qqCircleProgressBar.setCurrentProgress(currentTime);LoggerUtils.instance().logE("mediaPlayJindu", "mediaPlayJindu" + totalTime + "/" + currentTime);}sendEmptyMessageDelayed(MSG_FLUSH_SEEKBAR, MSG_FLUSH_TIME);}}}

在view使用时,初始化handler,构造参数传入组件id;

m_handler = new UpdateHandler(MediaPlayerIml.getInstance(),mSeekBar,mPrograssBar);
m_handler.sendEmptyMessage(MSG_FLUSH_SEEKBAR);

在view离开窗口时候,销毁handler数据;

  @Overrideprotected void onDetachedFromWindow() {super.onDetachedFromWindow();...if(m_handler!=null){m_handler.removeCallbacksAndMessages(null);m_handler = null;}}

总结

总结我们针对此按理做的优化

  1. 静态Handler+弱引用,释放了对handler对view的引用,让view及时销毁,view占据的内存及时被垃圾回收器释放
  2. 释放了Message对view的引用,在view及时退出界面的时候,立即斩断message对view
    回顾一下优化前的实例数量,多次操作,隐藏展示悬浮窗之后,内存中存在多份悬浮窗实例,之前创建过的悬浮窗内存一直无法被回收:
    在这里插入图片描述
    优化后效果,多次操作,当屏幕上存在一个view时,只存在一份view实例:
    [图片]
http://www.hkea.cn/news/816214/

相关文章:

  • 网站ip拦截免费网站搭建平台
  • 深圳企业网站建设公司快速申请免费个人网站
  • 唯品会 一家专门做特卖的网站沈阳seo按天计费
  • 聊城手机网站建设郑州seo服务技术
  • 个人定做衣服店江门seo推广公司
  • 网站开发与网站建设山东济南seo整站优化费用
  • 香港疫情最新消息今天深圳seo教程
  • 维护一个网站难吗免费发布外链
  • 南安市网站建设成都今天重大新闻事件
  • 网站后台补丁如何做软文有哪几种类型
  • 网站建设的费用包括哪些内容资讯门户类网站有哪些
  • 一站式服务图片制作网页的基本步骤
  • 个人网站建设网站网络网站推广
  • asp做的药店网站模板北京百度快照推广公司
  • 网站建设泉州效率网络seo的优化策略有哪些
  • 页网站无锡网站制作推广
  • 一流的龙岗网站建设目前最靠谱的推广平台
  • 企业营销型网站费用短视频推广引流
  • 化妆品可做的团购网站有哪些seo研究中心南宁线下
  • 网站空间域名是什么做电商必备的几个软件
  • 软件公司运营是做什么的seo公司运营
  • 专业云南做网站福州短视频seo服务
  • 网站开发技术期中试题电商培训机构排名
  • 网站设计连接数据库怎么做如何进行百度推广
  • 日本网站图片做淘宝代购网络营销促销方案
  • 网站开发导航栏网站制作的费用
  • 盐城网站设计网站流量统计工具
  • 网站上如何做相关推荐郑州建网站的公司
  • 漂亮大气的装潢室内设计网站模板 单页式html5网页模板包前端优化
  • 论坛网站开发开题报告青岛百度推广多少钱