美文网首页
VideoView的内存泄漏问题

VideoView的内存泄漏问题

作者: Aisen | 来源:发表于2019-01-28 00:43 被阅读44次

解决内存泄漏之路

一、在XML文件直接用VideoView控件时,很容易造成内存泄漏,最开始出现的内存泄漏如下

image.png

谷歌搜索了一下,最直接的解决方法是在代码中动态创建VideoView,传入的参数用Application

var mVideoView: VideoView? = null

if (mVideoView == null) {
     mVideoView = VideoView(MyApplication.appContext)
     video_view_container.addView(mVideoView, RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT))
}

二、这么修改后,还是会出现内存泄漏

image.png

这是VideoView的父View引起的,那么解决方法是在onDestory的时候,父View移除VideoView

override fun onDestroy() {
    mVideoView = null
    video_view_container?.removeAllViews()
    super.onDestroy()
}

三、为了避免出现其他内存泄漏,在Activity的onDestory时候,释放VideoView资源,置空listener

override fun onDestroy() {
    mVideoView?.suspend()
    mVideoView?.setOnErrorListener(null)
    mVideoView?.setOnPreparedListener(null)
    mVideoView?.setOnCompletionListener(null)

    mVideoView = null
    video_view_container?.removeAllViews()
    super.onDestroy()
}

四、以为这样就解决了VideoView的内存泄漏问题,但测着测着,竟然出现了崩溃,崩溃场景是视频播放不了,准备弹窗的时候,崩溃如下:

android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application

原因

创建VideoView,为解决内存泄漏,传入Application会有一个坑。VideoView在发生播放错误的时候,会有弹窗错误提示的Dialog,Dialog依赖传入mContext,如果是Application,那么会报崩溃。

解决方法

通过查看源码发现,在弹这个dialog的时候,会有条件判断,拦截这个条件不弹错误提示的Dialog即不会崩溃,然后这个Dialog在外部回调接口弹出。

这个拦截条件是VideoView的setOnErrorListener的实现方法返回true。

大功告成,既解决VideoView的内存泄漏,又解决了崩溃问题。

更进一步

虽然快速地解决了问题,但实际泄漏点的Root引用还没有好好分析,到底是哪个Root引用导致的内存泄漏?

泄漏点的root引用是PlayerBase$1.this$0(PlayeBase的子类是MediaPlayer),这是IAppsCallback$Stub的匿名类,在7.0系统可以看到

http://androidxref.com/7.0.0_r1/xref/frameworks/base/media/java/android/media/PlayerBase.java

mAppOpsCallback = new IAppOpsCallback.Stub() {
    public void opChanged(int op, int uid, String packageName) {
       synchronized (mAppOpsLock) {
           if (op == AppOpsManager.OP_PLAY_AUDIO) {
               updateAppOpsPlayAudio_sync();
          }
       }
    }
};

这个匿名内部类是Binder类,长生命周期持有短生命周期VideoPlayerActivit的引用,导致VideoPlayerActivit的泄漏

再进一步看,发现8.0以上的手机不会出现这个内存泄漏,原来是系统源码已经解决了这个内存泄漏

http://androidxref.com/8.0.0_r4/xref/frameworks/base/media/java/android/media/PlayerBase.java

处理方式是初始化mAppOpsCallback时,new 一个静态内部类,并且这个静态类传入的参数是弱引用

mAppOpsCallback = new IAppOpsCallbackWrapper(this);
private static class IPlayerWrapper extends IPlayer.Stub {
        private final WeakReference<PlayerBase> mWeakPB;

        public IPlayerWrapper(PlayerBase pb) {
            mWeakPB = new WeakReference<PlayerBase>(pb);
       }
       ....
}

(从AOSP的提交记录可以看出,这是8.0开始做的修复)

相关文章

  • VideoView的内存泄漏问题

    解决内存泄漏之路 一、在XML文件直接用VideoView控件时,很容易造成内存泄漏,最开始出现的内存泄漏如下 谷...

  • 关于Android VideoView导致的内存泄漏的问题

    泄露信息如下: ==================================== HEAP ANALY...

  • Xcode调试工具

    一.静态内存分析工具 编译阶段查找内存泄漏等问题 1.常见内存泄漏问题 常见的内存泄漏除了循环引用,CoreFou...

  • 三个方法帮助解决Android内存泄漏问题

    三个方法帮助解决Android内存泄漏问题 最近自己遇到了好几个内存泄漏的问题,也帮同事解决了几个内存泄漏的问题记...

  • 安卓内存泄漏

    Android 内存泄漏总结 内存管理的目的就是让我们在开发中怎么有效的避免我们的应用出现内存泄漏的问题。内存泄漏...

  • Part1_Android内存泄漏总结

    Android 内存泄漏总结 内存管理的目的就是让我们在开发中怎么有效的避免我们的应用出现内存泄漏的问题。内存泄漏...

  • Android 内存泄漏总结

    Android 内存泄漏总结 内存管理的目的就是让我们在开发中怎么有效的避免我们的应用出现内存泄漏的问题。内存泄漏...

  • 【中级——高级迈不过去?】Android高级工程师进阶学习——A

    Android 内存泄漏总结 内存管理的目的就是让我们在开发中怎么有效的避免我们的应用出现内存泄漏的问题。内存泄漏...

  • Android内存泄漏相关

    问题1 内存泄漏的基本定义是什么?内存泄漏有什么危害?问题2 开发中常见的内存泄漏的情况有哪些?什么原因造成的?怎...

  • 内存泄漏

    内存问题的可能情况 内存泄漏(memory leak)指由于疏忽或错误造成程序未能释放已经不再使用的内存。内存泄漏...

网友评论

      本文标题:VideoView的内存泄漏问题

      本文链接:https://www.haomeiwen.com/subject/kjjojqtx.html