关于Android VideoView导致的内存泄漏的问题
来源:互联网 发布:nginx 伪静态 编辑:程序博客网 时间:2024/06/04 18:33
今天用 leakcanary 时发现用VideoView的 activity 出现泄漏,捕获到如下的信息,简单说就是 android M(6.0)以前AudioManager用的Context是 当前传入的,当activity finish之后 AudioManager依然保持对它的引用,所以就leak了,6.0后改用ApplicationContext修复了此问题,google后发现下面这种解决方法也不错
首先声明,下面的文章是我转载的,感谢原作者的分享,来源https://blog.yeatse.com/2015/11/01/android-video-view-memory-leak
最近在做的项目里要实现在Android中播放视频这么一个需求。功能本身并不复杂,因为赶时间图省事,没有用Android底层的MediaPlayer API,直接用了谷歌封装好的VideoView
组件:
12345678910111213141516171819202122232425262728
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="fill_parent"android:layout_height="fill_parent"android:background="@android:color/black"><RelativeLayoutandroid:id="@+id/videoContainer"android:layout_width="fill_parent"android:layout_height="fill_parent"><VideoViewandroid:id="@+id/videoView"android:layout_width="fill_parent"android:layout_height="fill_parent"android:layout_centerInParent="true"/><Viewandroid:id="@+id/placeHolder"android:layout_width="fill_parent"android:layout_height="fill_parent"android:background="@android:color/black"/></RelativeLayout><!-- ...... --></RelativeLayout>
像这样在XML里声明一下,然后调用setVideoPath
方法传入视频路径,start
、pause
和stopPlayback
方法控制播放,基本功能就做好啦。可喜可贺,可喜可贺。
但是在实机运行时,我发现即使关闭了含有VideoView的Activity,它申请到的内存也不会被释放。多次进入这个页面再关闭的话,程序占用的内存越来越多,用Android Studio自带的Java Heap Dump功能可以看到这些Activity都没有被回收掉,显然在某些地方出现了内存泄漏。经过一番仔细排查,问题定位到了VideoView.setVideoPath
方法上,屏蔽掉这一行,Activity就可以正常被回收;把这一行加回来,问题又出现了。
这个方法是用来给VideoView传视频url的,当然不能删掉了事,于是开google,看到有人在天国的google code上讨论过这个问题。大体意思是说,VideoView内部的AudioManager
会对Activity持有一个强引用,而AudioManager
的生命周期比较长,导致这个Activity始终无法被回收,这个bug直到2015年5月才被谷歌修复。因为Activity是通过VideoView的构造函数传给AudioManager的,所以回复里有人提出了一个workaround:不要用XML声明VideoView,改用代码动态创建,创建的时候把全局的Context传给VideoView,而不是Activity本身。试了一下果然可行:
12345
videoView = new VideoView(getApplicationContext());RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);params.addRule(RelativeLayout.CENTER_IN_PARENT);videoView.setLayoutParams(params);((RelativeLayout)findViewById(R.id.videoContainer)).addView(videoView, 0);
这样做到底还是感觉不太优雅,且不说动态创建和XML声明混到一起后期难维护,直接传全局Context总觉得程序会在哪个魔改rom上就崩掉了。考虑到内存泄漏的原因出在AudioManager上,所以只针对它作处理就足够了。于是把VideoView放回XML里,重写Activity.attachBaseContext
方法:
123456789101112131415
protected void attachBaseContext(Context newBase){super.attachBaseContext(new ContextWrapper(newBase){public Object getSystemService(String name){if (Context.AUDIO_SERVICE.equals(name))return getApplicationContext().getSystemService(name);return super.getSystemService(name);}});}
重新调试,为了方便跟踪回收事件我在finalize
方法中加了一行log,关闭Activity之后调用System.gc()
,果然有回收的log输出,问题解决。
- 关于Android VideoView导致的内存泄漏的问题
- 关于Android VideoView导致的内存泄漏的问题
- 常见的导致Android内存泄漏问题
- 关于ExitInstance不执行,导致很多内存泄漏的问题
- Android:关于ListView的内存泄漏问题
- 再谈android内存泄漏—常见的八种导致 APP 内存泄漏的问题
- Android handler导致的内存泄漏
- Android Handler导致内存泄漏的解决方案
- Android AsyncTask导致的内存泄漏
- 关于内存泄漏的问题
- 关于内存泄漏的问题
- 关于内存泄漏的问题
- 关于Android中的内存溢出和内存泄漏的问题
- Android异常一、异步任务导致的窗口句柄泄漏问题(内存泄漏)
- 内存分配不成功导致内存泄漏的问题
- 关于Android handler内存泄漏问题的测试与解决
- 导致内存泄漏的原因
- ThreadLocal 导致的内存泄漏
- Ubuntu下使用supervisor设置脚本开机自启
- 功耗优化方法
- php 单例模式demo
- 基础最短路五 POJ1860
- 简单地用swing写一个登陆页面
- 关于Android VideoView导致的内存泄漏的问题
- 在Qt Linux环境下编译使用libevent
- linux 编译ffmpeg 支持x264, x265
- 有关Java从数据库查询出的数据导出Excel POI分页功能总结
- java编程思想 -- java概述
- MergeDelta增加写ORC格式功能
- <column name="USERID" precision="10" scale="0" />什么意思???
- 启动APK不现实主界面直接跳转网页会出现
- C#之switch多分支语句