我是靠谱客的博主 明亮冬天,最近开发中收集的这篇文章主要介绍android videoview 释放资源,关于Android VideoView导致的内存泄漏的问题,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

今天用 leakcanary 时发现用VideoView的 activity 出现泄漏,捕获到如下的信息,简单说就是 android M(6.0)以前AudioManager用的Context是 当前传入的,当activity finish之后 AudioManager依然保持对它的引用,所以就leak了,6.0后改用ApplicationContext修复了此问题,google后发现下面这种解决方法也不错

e696864c01efa866ef1e5f3798cfdfc6.png

首先声明,下面的文章是我转载的,感谢原作者的分享,来源https://blog.yeatse.com/2015/11/01/android-video-view-memory-leak

最近在做的项目里要实现在Android中播放视频这么一个需求。功能本身并不复杂,因为赶时间图省事,没有用Android底层的MediaPlayer API,直接用了谷歌封装好的VideoView组件:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

android:layout_width=

"fill_parent"

android:layout_height=

"fill_parent"

android:background=

"@android:color/black">

android:id=

"@+id/videoContainer"

android:layout_width=

"fill_parent"

android:layout_height=

"fill_parent">

android:id=

"@+id/videoView"

android:layout_width=

"fill_parent"

android:layout_height=

"fill_parent"

android:layout_centerInParent=

"true"/>

android: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本身。试了一下果然可行:

1

2

3

4

5

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方法:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

@Override

protected void attachBaseContext(Context newBase)

{

super.attachBaseContext(

new ContextWrapper(newBase)

{

@Override

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 videoview 释放资源,关于Android VideoView导致的内存泄漏的问题所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(33)

评论列表共有 0 条评论

立即
投稿
返回
顶部