Android ImageView.setImageResource 出现 栈溢出问题 StackOverflowError

    1. 背景

    今天在测试应用的时候出现一个问题,分析之后,我觉得特别奇怪,可以看下面的报错:

E/AndroidRuntime(29778): java.lang.StackOverflowError

E/AndroidRuntime(29778): 	at android.graphics.drawable.BitmapDrawable.computeBitmapSize(BitmapDrawable.java:189)

E/AndroidRuntime(29778): 	at android.graphics.drawable.BitmapDrawable.setBitmap(BitmapDrawable.java:197)

E/AndroidRuntime(29778): 	at android.graphics.drawable.BitmapDrawable.<init>(BitmapDrawable.java:689)

E/AndroidRuntime(29778): 	at android.graphics.drawable.BitmapDrawable.<init>(BitmapDrawable.java:62)

E/AndroidRuntime(29778): 	at android.graphics.drawable.BitmapDrawable$BitmapState.newDrawable(BitmapDrawable.java:673)

E/AndroidRuntime(29778): 	at android.content.res.Resources.getCachedDrawable(Resources.java:2183)

E/AndroidRuntime(29778): 	at android.content.res.Resources.loadDrawable(Resources.java:2048)

E/AndroidRuntime(29778): 	at android.content.res.Resources.getDrawable(Resources.java:700)

E/AndroidRuntime(29778): 	at androidx.appcompat.widget.ResourcesWrapper.getDrawable(ResourcesWrapper.java:130)

E/AndroidRuntime(29778): 	at androidx.appcompat.widget.TintResources.getDrawable(TintResources.java:46)

E/AndroidRuntime(29778): 	at androidx.core.content.ContextCompat.getDrawable(ContextCompat.java:456)

E/AndroidRuntime(29778): 	at androidx.appcompat.widget.ResourceManagerInternal.getDrawable(ResourceManagerInternal.java:144)

E/AndroidRuntime(29778): 	at androidx.appcompat.widget.ResourceManagerInternal.getDrawable(ResourceManagerInternal.java:132)

E/AndroidRuntime(29778): 	at androidx.appcompat.content.res.AppCompatResources.getDrawable(AppCompatResources.java:104)

E/AndroidRuntime(29778): 	at androidx.appcompat.widget.AppCompatImageHelper.setImageResource(AppCompatImageHelper.java:86)

E/AndroidRuntime(29778): 	at androidx.appcompat.widget.AppCompatImageView.setImageResource(AppCompatImageView.java:94)

E/AndroidRuntime(29778): 	at plat.skytv.main.activity.CpappDetailActivity.updateUiAsVip(CpappDetailActivity.java:705)

2. 分析

    2.1 首先 我的疑问在 仅仅 调用了 一次 ImageView.setImageResource(int resourceid); 怎么就蹦了了,而且不是OOM,而是堆栈溢出。

    2.2 其次 这个不是系统的方法嘛,难道调用系统的方法也不行了嘛,为此我还想过 使用Glide去加载图片。

    2.3 最后看了一篇文章,虽然 发生错误的原因不同,但是结果却是相同的,让我有了一点思路。

    2.4 检查代码逻辑之后,发现是 两个方法递归调用,虽然里面并没有复杂的逻辑,但是却一直在调用 ImageView.setImageResource。

    2.5 然后我又去看了下 StackOverflowErrorOutOfMemoryError 的区别:

        StackOverflowError :是Java线程操作是基于栈的,如果两个方法循环调用,就会一直进栈而不会出栈,如果栈的深度超过了虚拟机所允许的深度,就会抛出这个问题。

        OutOfMemoryError:栈的深度是可以自动扩展的,但是如果扩展时无法申请到足够的内存时就会OOM。

3. 解答

    3.1 因为我的问题是android 4.4 的盒子上出现的,就去看了 4.4 的源码,然后看到了这么一句:

    public void setImageResource(int resId) {
            ...
    
            resolveUri();

            ...
        }
    }

    然后 看一下 这个 resolveUri 方法主要干了啥:

private void resolveUri() {
            ...
                d = rsrc.getDrawable(mResource);
            ...
    }

   然后一路跟进去会到 loadDrawable 这个方法:

Drawable loadDrawable(TypedValue value, int id)
            throws NotFoundException {

        ...

        Drawable dr = getCachedDrawable(isColorDrawable ? mColorDrawableCache : mDrawableCache, key);

        if (dr != null) {
            return dr;
        }

        ...

        return dr;
    }

   看到这我就明白了,代码在循环调用的时候,应该是从缓存中去取了已经加载好的图片,不会去创建新的Bitmap,所以并没有OOM的问题。

4. 总结

    4.1 如果发生 StackOverflowError 的问题,在问题代码前后需要看下时候有递归调用,这个很重要。

    4.2 记得 分析日志,android系统已经是一个相对比较完善的生态,必然不会无缘无故的报错崩溃,在崩溃前后肯定有一些蛛丝马迹,善于分析,然后网上查找资料,扩充知识库,不仅找你发生的问题,最好源码也分析一遍,加深印象。

    4.3 参考:

        https://www.kanzhun.com/mianshiti/496991.html

        https://blog.csdn.net/u012410733/article/details/53464295

        https://blog.csdn.net/Icannotdebug/article/details/78844619​​​​​​​

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值