panpf / sketch

Sketch is an image loading library designed for Compose Multiplatform and Android View. It is powerful and rich in functions. In addition to basic functions, it also supports GIF, SVG, video thumbnails, Exif Orientation, etc.
Apache License 2.0
2.07k stars 308 forks source link

图片加载失败导致应用崩溃 #176

Closed lr555 closed 1 year ago

lr555 commented 1 year ago

图片加载失败导致应用崩溃,下面是日志。请问在imageView.displayImage加上try catch可以避免崩溃吗?还是要在其他地方处理?

0 java.io.IOException: HTTP code error. code=401, message=. xxx 1 com.github.panpf.sketch.fetch.HttpUriFetcher$executeFetch$2.invokeSuspend(HttpUriFetcher.java:97) 2 kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(BaseContinuationImpl.java:33) 3 kotlinx.coroutines.DispatchedTask.run(DispatchedTask.java:106) 4 kotlinx.coroutines.internal.LimitedDispatcher.run(LimitedDispatcher.java:42) 5 kotlinx.coroutines.scheduling.TaskImpl.run(TaskImpl.java:95) 6 kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.java:570) 7 kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.java:750) 8 kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.java:677) 9 kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.java:664)

panpf commented 1 year ago

经测试,该异常会被捕获,不会导致 App 崩溃,完整日志如下:

main - RequestExecutor. Request failed. java.io.IOException: HTTP code error. code=200, message=. https://images.pexels.com/photos/16253956/pexels-photo-16253956.jpeg?auto=compress&cs=tinysrgb&h=350. 'https://images.pexels.com/photos/16253956/pexels-photo-16253956.jpeg?auto=compress&cs=tinysrgb&h=350&_parameters=Parameters(app#imageType:LIST)&_resize=Resize(345x345,Fixed(LESS_PIXELS),Fixed(CENTER_CROP))' --> 'https://images.pexels.com/photos/16253956/pexels-photo-16253956.jpeg?auto=compress&cs=tinysrgb&h=350&_parameters=Parameters(app#imageType:LIST)&_resize=Resize(345x345,LongImageClip(SAME_ASPECT_RATIO,Default(2.5,5.0)),LongImage(START_CROP,CENTER_CROP),Default(2.5,5.0)))'
com.github.panpf.sketch.util.UnknownException: java.io.IOException: HTTP code error. code=200, message=. https://images.pexels.com/photos/16253956/pexels-photo-16253956.jpeg?auto=compress&cs=tinysrgb&h=350
   at com.github.panpf.sketch.request.internal.RequestExecutor.execute(RequestExecutor.kt:143)
   at com.github.panpf.sketch.request.internal.RequestExecutor$execute$1.invokeSuspend(RequestExecutor.kt)
   at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
   at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:104)
   at android.os.Handler.handleCallback(Handler.java:739)
   at android.os.Handler.dispatchMessage(Handler.java:95)
   at android.os.Looper.loop(Looper.java:135)
   at android.app.ActivityThread.main(ActivityThread.java:5221)
   at java.lang.reflect.Method.invoke(Native Method)
   at java.lang.reflect.Method.invoke(Method.java:372)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
Caused by: java.io.IOException: HTTP code error. code=200, message=. https://images.pexels.com/photos/16253956/pexels-photo-16253956.jpeg?auto=compress&cs=tinysrgb&h=350
   at com.github.panpf.sketch.fetch.HttpUriFetcher$executeFetch$2.invokeSuspend(HttpUriFetcher.kt:97)
   at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
   at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
   at kotlinx.coroutines.internal.LimitedDispatcher.run(LimitedDispatcher.kt:42)
   at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:95)
   at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
   at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
   at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)
   at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)

如有异议,请升级到最新版本,并提供完整测试用例及说明测试环境

lr555 commented 1 year ago

经测试,该异常会被捕获,不会导致 App 崩溃,完整日志如下:

main - RequestExecutor. Request failed. java.io.IOException: HTTP code error. code=200, message=. https://images.pexels.com/photos/16253956/pexels-photo-16253956.jpeg?auto=compress&cs=tinysrgb&h=350. 'https://images.pexels.com/photos/16253956/pexels-photo-16253956.jpeg?auto=compress&cs=tinysrgb&h=350&_parameters=Parameters(app#imageType:LIST)&_resize=Resize(345x345,Fixed(LESS_PIXELS),Fixed(CENTER_CROP))' --> 'https://images.pexels.com/photos/16253956/pexels-photo-16253956.jpeg?auto=compress&cs=tinysrgb&h=350&_parameters=Parameters(app#imageType:LIST)&_resize=Resize(345x345,LongImageClip(SAME_ASPECT_RATIO,Default(2.5,5.0)),LongImage(START_CROP,CENTER_CROP),Default(2.5,5.0)))'
com.github.panpf.sketch.util.UnknownException: java.io.IOException: HTTP code error. code=200, message=. https://images.pexels.com/photos/16253956/pexels-photo-16253956.jpeg?auto=compress&cs=tinysrgb&h=350
   at com.github.panpf.sketch.request.internal.RequestExecutor.execute(RequestExecutor.kt:143)
   at com.github.panpf.sketch.request.internal.RequestExecutor$execute$1.invokeSuspend(RequestExecutor.kt)
   at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
   at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:104)
   at android.os.Handler.handleCallback(Handler.java:739)
   at android.os.Handler.dispatchMessage(Handler.java:95)
   at android.os.Looper.loop(Looper.java:135)
   at android.app.ActivityThread.main(ActivityThread.java:5221)
   at java.lang.reflect.Method.invoke(Native Method)
   at java.lang.reflect.Method.invoke(Method.java:372)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
Caused by: java.io.IOException: HTTP code error. code=200, message=. https://images.pexels.com/photos/16253956/pexels-photo-16253956.jpeg?auto=compress&cs=tinysrgb&h=350
   at com.github.panpf.sketch.fetch.HttpUriFetcher$executeFetch$2.invokeSuspend(HttpUriFetcher.kt:97)
   at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
   at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
   at kotlinx.coroutines.internal.LimitedDispatcher.run(LimitedDispatcher.kt:42)
   at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:95)
   at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
   at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
   at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)
   at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)

如有异议,请升级到最新版本,并提供完整测试用例及说明测试环境

bugly上偶发的崩溃,使用的sketch相关库版本都是3.2.0,imageView使用的是SketchZoomImageView

panpf commented 1 year ago

我再研究研究协程中捕获异常的情况,可能需要在特定的条件下才能复现

lr555 commented 1 year ago

我再研究研究协程中捕获异常的情况,可能需要在特定的条件下才能复现

有没有方法直接在程序里面try catch这个异常,比如说在imageView.displayImage加上try catch,不是很了解kotlin协程,但是确实在bugly里有上报

lr555 commented 1 year ago

补充一下报错日志

--------- beginning of crash
2023-04-17 16:35:03.994  4328-4328  AndroidRuntime          pid-4328                             E  FATAL EXCEPTION: main
                                                                                                    Process: com.myApp, PID: 4328
                                                                                                    java.io.IOException: HTTP code error. code=401, message=Unauthorized. https://xxx.img
                                                                                                        at com.github.panpf.sketch.fetch.HttpUriFetcher$executeFetch$2.invokeSuspend(HttpUriFetcher.kt:97)
                                                                                                        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
                                                                                                        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
                                                                                                        at kotlinx.coroutines.internal.LimitedDispatcher.run(LimitedDispatcher.kt:42)
                                                                                                        at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:95)
                                                                                                        at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
                                                                                                        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
                                                                                                        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)
                                                                                                        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)
                                                                                                        Suppressed: kotlinx.coroutines.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@bc91194, Dispatchers.Main]
panpf commented 1 year ago

我再研究研究协程中捕获异常的情况,可能需要在特定的条件下才能复现

有没有方法直接在程序里面try catch这个异常,比如说在imageView.displayImage加上try catch,不是很了解kotlin协程,但是确实在bugly里有上报

  1. diaplayImage 方法是异步执行的,你 catch 它没用。
  2. 目前已经在可能的最外面 try catch 了,依然又漏网之鱼。
  3. 主动在此位置抛出异常测试,是可以捕获的,说明还需要满足特定的条件才能触发无法捕获的 bug,现在这个特定条件不明朗,还需要测试以及查资料。
lr555 commented 1 year ago

我是使用ViewPager2,里面使用的是SketchZoomImageView加载图片

viewPager的代码:

mBinding.viewPager.setOffscreenPageLimit(1);
GalleryRecyclerAdapter adapter = new GalleryRecyclerAdapter(mImages);
mBinding.viewPager.setAdapter(adapter);
mBinding.viewPager.setCurrentItem(mIndex, false);

adapter的主要代码:

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.bind(mImageUrls[position])
}

class ViewHolder(private val mBinding: ItemRecyclerViewBinding) : RecyclerView.ViewHolder(mBinding.root) {
       ...
        fun bind(imageUrl: String) {
            val model = CustomImageModel(imageUrl)
            mBinding.itemImage.apply {
                readModeEnabled = false
                displayImage(model.url) {
                    placeholder(R.drawable.loading)
                    error(R.drawable.loading)
                    httpHeaders(model.headers)
                    listener(
                        onStart = {

                        },
                        onSuccess = { _, result ->

                        },
                        onError = { _, result ->

                        }
                    )
                }

                setOnClickListener {

                }

                setOnLongClickListener {

                }
            }
        }
...
}

附上Google Suppressed: kotlinx.coroutines.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}, Dispatchers.Main]这个异常的相关链接:

  1. https://stackoverflow.com/questions/74242671/dispatcher-main-raising-exception
  2. https://stackoverflow.com/questions/60185192/throw-kotlinx-coroutines-jobcancellationexception-when-go-to-another-screen
lr555 commented 1 year ago

不好意思,项目最近要上线了,我尝试使用glide和SketchZoomImageView加载图片,做兜底方案,但是加载大图的时候报错了,请问有什么解决方法吗? 代码如下:

// itemImage是SketchZoomImageView
itemImage.scaleType = ImageView.ScaleType.CENTER

Glide.with(mContext)
                .load(url)
                .placeholder(placeholder)
                .listener(
                    object : RequestListener<Drawable> {

                        override fun onResourceReady(
                            resource: Drawable?,
                            model: Any?,
                            target: com.bumptech.glide.request.target.Target<Drawable>?,
                            dataSource: DataSource?,
                            isFirstResource: Boolean
                        ): Boolean {
                            itemImage.scaleType = ImageView.ScaleType.FIT_CENTER
                            return false
                        }

                        override fun onLoadFailed(
                            e: GlideException?,
                            model: Any?,
                            target: com.bumptech.glide.request.target.Target<Drawable>?,
                            isFirstResource: Boolean
                        ): Boolean {
                            return false
                        }
                    }
                )
                .into(itemImage)

报错如下:

java.lang.RuntimeException: Canvas: trying to draw too large(146286720bytes) bitmap.
panpf commented 1 year ago

那你就大图部分用sketch,列表用glide 吧,但尽量不要混着用

panpf commented 1 year ago

方便给我看一下 bugly 上这个崩溃的 Android 版本分布吗?我想知道都在哪些版本上会出错

lr555 commented 1 year ago

目前只在两台手机上测试了,下面是设备信息

  1. 荣耀

    image
  2. pixel

    image
panpf commented 1 year ago

你进 QQ 群,我们详细沟通一下吧 529630740

pzllla commented 1 year ago

感觉可以看一下coil有没有类似的情况?都是用协程进行image加载的。issue里面这个看上去可能有关联 https://github.com/coil-kt/coil/issues/1606

pzllla commented 1 year ago

https://github.com/coil-kt/coil/issues/589https://github.com/coil-kt/coil/issues/431 ,这里说CancellationExceptions是特殊的,可以看看是不是这个问题

panpf commented 1 year ago

目前已经初步定位到是跟协程内部的异常传递与捕获有关,主要还是不太了解这部分,无法准确复现

panpf commented 1 year ago

还在恶补相关知识,努力复现,才能修复

panpf commented 1 year ago

目前虽然无法复现,但是已经有了解决方案,这几天就会发布新的版本

lr555 commented 1 year ago

非常感谢!发了新版,麻烦踢一脚♪(・ω・)ノ

panpf commented 1 year ago

非常感谢!发了新版,麻烦踢一脚♪(・ω・)ノ

已经发了新的测试版 3.2.1-beta01 你可以更新一下,然后你们的 App 发个灰度版本试试,我们的 App 也在发灰度测试

lr555 commented 1 year ago

非常感谢!发了新版,麻烦踢一脚♪(・ω・)ノ

已经发了新的测试版 3.2.1-beta01 你可以更新一下,然后你们的 App 发个灰度版本试试,我们的 App 也在发灰度测试

👌🏻,非常感谢,我把sketch版本升级一下,再测试一下。其他库我看代码没改动,我这边就不改版本了

panpf commented 1 year ago

最好是一起升级

lr555 commented 1 year ago

okok

lr555 commented 1 year ago

我是使用ViewPager2,里面使用的是SketchZoomImageView加载图片

还是有这个问题,现在我找到一个复现方法,在网络较差环境下(如移动数据),然后在viewpager2一次性滑动多张图片(多张图片同时在加载),不断滑动,如果有请求失败了,就会crash

image
panpf commented 1 year ago

你先将运行环境信息贴一下,包括 Android 版本,手机型号,最终的Activityx 版本、Fragment 版本、 ViewPager 版本,kotlin 版本、协程版本等 然后我试试能不能复现,你也帮忙看看能否搞一个能复现问题的 demo 出来

lr555 commented 1 year ago

Android版本:Android 13,level 33, 手机型号:Pixel 6 Pro, Activityx 版本:androidx.appcompat:appcompat:1.6.0 Fragment版本:androidx.fragment:fragment:1.0.0 ViewPager2版本:androidx.viewpager2:viewpager2:1.0.0 kotlin版本和协程:

image

我看一下能不能整一个demo出来,主要是都是内网图片,我看下用其他图片链接能不能复现出来

lr555 commented 1 year ago

不好意思,有点事情要忙,暂时没工夫处理这个bug。 发现viewpager2包含多个大图时,容易出现这个问题,但是有可能是我的应用导致的,和sketch没关系, 用外网图片难以复现,实在是诡异,下面是一些大图链接,可以测试一下。提前祝五一快乐!

"https://upload.wikimedia.org/wikipedia/commons/3/3f/Francisco_de_Goya_y_Lucientes_-_Los_fusilamientos_del_tres_de_mayo_-_1814.jpg"

"https://mathiasbynens.be/demo/animated-webp-supported.webp"

"https://upload.wikimedia.org/wikipedia/commons/9/99/Las_Meninas_01.jpg"

"https://upload.wikimedia.org/wikipedia/commons/2/2c/Rotating_earth_%28large%29.gif"

"https://upload.wikimedia.org/wikipedia/commons/f/f1/El_caballero_de_la_mano_en_el_pecho.jpg"

"https://upload.wikimedia.org/wikipedia/commons/a/aa/SmallFullColourGIF.gif"

"https://upload.wikimedia.org/wikipedia/commons/6/62/The_Garden_of_Earthly_Delights_by_Bosch_High_Resolution_2.jpg"

"https://upload.wikimedia.org/wikipedia/commons/f/fb/La_Anunciaci%C3%B3n_%28Fra_Angelico-Prado%29.jpg"

"https://upload.wikimedia.org/wikipedia/commons/thumb/d/d2/Carlos_V_en_M%C3%BChlberg%2C_by_Titian%2C_from_Prado_in_Google_Earth.jpg/3000px-Carlos_V_en_M%C3%BChlberg%2C_by_Titian%2C_from_Prado_in_Google_Earth.jpg"

"https://upload.wikimedia.org/wikipedia/commons/b/bb/Rembrandt_Harmensz._van_Rijn_014.jpg"

"https://upload.wikimedia.org/wikipedia/commons/1/16/Raffael_048.jpg"

"https://upload.wikimedia.org/wikipedia/commons/d/d4/Crucifixi%C3%B3n_Juan_de_Flandes.jpg"

"https://upload.wikimedia.org/wikipedia/commons/d/da/Albrecht_D%C3%BCrer_103.jpg"

"https://upload.wikimedia.org/wikipedia/commons/1/1a/Weyden_Deposition.jpg"

"https://upload.wikimedia.org/wikipedia/commons/b/b6/El_sue%C3%B1o_de_Jacob%2C_por_Jos%C3%A9_de_Ribera.jpg"

"https://upload.wikimedia.org/wikipedia/commons/8/8b/Giovanni_Battista_Tiepolo_022.jpg"
lr555 commented 1 year ago

我使用coil和SketchZoomImageView加载图片,现在没有这个问题了,查看大图也ok。 下面是加载的代码,如果有朋友遇到类似问题的,可以参考一下:

  1. app的build.gradle引入依赖

    // 支持手势缩放
    implementation "io.github.panpf.sketch3:sketch-extensions:3.2.1-beta01" 
    // 需要引入sketch-extensions,不然viewpager2里屏幕旋转,图片会错位
    implementation "io.github.panpf.sketch3:sketch-zoom:3.2.1-beta01"
    // coil 图片加载库
    implementation "io.coil-kt:coil:2.3.0"
    implementation "io.coil-kt:coil-gif:2.3.0"
    implementation "io.coil-kt:coil-svg:2.3.0"
  2. 在viewpager2的adapter里,加载图片 其中mBinding.itemImage是SketchZoomImageView

    
    class GalleryRecyclerAdapter(private val mImageUrls: List<String>) :
    RecyclerView.Adapter<GalleryRecyclerAdapter.ViewHolder>() {
    
    override fun getItemCount(): Int {
        return mImageUrls.size
    }
    
    class ViewHolder(private val mBinding: ItemRecyclerViewBinding) : RecyclerView.ViewHolder(mBinding.root) {
        init {
            // 设置单击和长按事件
            mBinding.itemImage.apply {
                setOnClickListener {
    
                }
    
                setOnLongClickListener {
                    return@setOnLongClickListener true
                }
            }
        }
    
        fun bind(imageUrl: String) {
            val model = CustomImageModel(imageUrl)
            // mBinding.itemImage是SketchZoomImageView
            mBinding.itemImage.apply {
                // 长图阅读模式关闭
                readModeEnabled = false
                scaleType = ImageView.ScaleType.CENTER
                // 使用coil加载图片
                load(model.url) {
                    crossfade(false)
                    placeholder(R.drawable.loading)
                    error(R.drawable.loading)
                    size(ViewSizeResolver(mBinding.itemImage))
                    allowHardware(true)
                    // 特殊图片 需要加上header访问 一般可不加
                    headers(model.headers)
                    listener(
                        onStart = {
                            // placeholder和error不拉伸
                            mBinding.itemImage.scaleType = ImageView.ScaleType.CENTER
                        },
                        onSuccess = { _, result ->
                            // 结果图全屏
                            mBinding.itemImage.scaleType = ImageView.ScaleType.FIT_CENTER
                        },
                        onError = { _, result ->
                        }
                    )
                }
            }
        }
    }
    
    override fun getItemId(i: Int): Long {
        return i.toLong()
    }
    
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val binding = ItemRecyclerViewBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return ViewHolder(binding)
    }
    
    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.bind(mImageUrls[position])
    }
    
    override fun getItemViewType(i: Int): Int {
        return 0
    }

}

panpf commented 1 year ago

我们的 App 上线后还是有这个问题,不过数量很少了,最近十几天平均一万日活的情况下只出现过一次。

另外你的这个解决办法有点无奈,这样就引入了两个图片加载库,对 App 的内存压力很大(因为会有两块内存缓存)。

我还在寻找新的办法解决这个问题,你这边要是有新的情况或复现的办法可以多多交流。

lr555 commented 1 year ago

我使用coil和SketchZoomImageView加载图片,现在没有这个问题了,查看大图也ok。 下面是加载的代码,如果有朋友遇到类似问题的,可以参考一下:

  1. app的build.gradle引入依赖
// 支持手势缩放
implementation "io.github.panpf.sketch3:sketch-extensions:3.2.1-beta01" 
// 需要引入sketch-extensions,不然viewpager2里屏幕旋转,图片会错位
implementation "io.github.panpf.sketch3:sketch-zoom:3.2.1-beta01"
// coil 图片加载库
implementation "io.coil-kt:coil:2.3.0"
implementation "io.coil-kt:coil-gif:2.3.0"
implementation "io.coil-kt:coil-svg:2.3.0"
  1. 在viewpager2的adapter里,加载图片 其中mBinding.itemImage是SketchZoomImageView
class GalleryRecyclerAdapter(private val mImageUrls: List<String>) :
    RecyclerView.Adapter<GalleryRecyclerAdapter.ViewHolder>() {

    override fun getItemCount(): Int {
        return mImageUrls.size
    }

    class ViewHolder(private val mBinding: ItemRecyclerViewBinding) : RecyclerView.ViewHolder(mBinding.root) {
        init {
            // 设置单击和长按事件
            mBinding.itemImage.apply {
                setOnClickListener {

                }

                setOnLongClickListener {
                    return@setOnLongClickListener true
                }
            }
        }

        fun bind(imageUrl: String) {
            val model = CustomImageModel(imageUrl)
            // mBinding.itemImage是SketchZoomImageView
            mBinding.itemImage.apply {
                // 长图阅读模式关闭
                readModeEnabled = false
                scaleType = ImageView.ScaleType.CENTER
                // 使用coil加载图片
                load(model.url) {
                    crossfade(false)
                    placeholder(R.drawable.loading)
                    error(R.drawable.loading)
                    size(ViewSizeResolver(mBinding.itemImage))
                    allowHardware(true)
                    // 特殊图片 需要加上header访问 一般可不加
                    headers(model.headers)
                    listener(
                        onStart = {
                            // placeholder和error不拉伸
                            mBinding.itemImage.scaleType = ImageView.ScaleType.CENTER
                        },
                        onSuccess = { _, result ->
                            // 结果图全屏
                            mBinding.itemImage.scaleType = ImageView.ScaleType.FIT_CENTER
                        },
                        onError = { _, result ->
                        }
                    )
                }
            }
        }
    }

    override fun getItemId(i: Int): Long {
        return i.toLong()
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val binding = ItemRecyclerViewBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return ViewHolder(binding)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.bind(mImageUrls[position])
    }

    override fun getItemViewType(i: Int): Int {
        return 0
    }

}

我这里只引入了sketch-extensions和sketch-zoom两个库,只用coil加载图片(没有引入sketch库来进行加载),也会有两块缓存吗?这感觉不太合理吧?

panpf commented 1 year ago

zoom是依赖sketch的,你要是没用zoomimageview 的 displayimage 方法是不会开辟新的内存缓存的,但相关代码全都引入了,用起来要很小心

panpf commented 1 year ago

3.2.1-beta02 版本发布了,这次改了架构来修复这个问题,应该可以彻底解决这个问题,你可以再试试

panpf commented 1 year ago

我们的项目上了 3.2.1-rc01 版本,已经一万多用户了,线上没有再收到这个崩溃报告。你可以再试试了

lr555 commented 1 year ago

好的,我试试3.2.1-rc01这个版本,测几天观察一下

lr555 commented 1 year ago

还是存在这个问题,用3.2.1-rc01和3.2.1-rc02都测了,都有这个崩溃。哥们要不参考一下coil的架构,改进一下?

image
#2 main
java.io.IOException
HTTP code error. code=401, message=Unauthorized. https://xxx

0 java.io.IOException: HTTP code error. code=401, message=Unauthorized.  https://xxx
1 com.github.panpf.sketch.fetch.HttpUriFetcher$fetch$2.k(HttpUriFetcher.java:127)
2 kotlin.coroutines.jvm.internal.BaseContinuationImpl.void resumeWith(java.lang.Object)(BaseContinuationImpl.java:33)
3 kotlinx.coroutines.DispatchedTask.void run()(DispatchedTask.java:106)
4 kotlinx.coroutines.internal.LimitedDispatcher.void run()(LimitedDispatcher.java:42)
5 kotlinx.coroutines.scheduling.TaskImpl.void run()(TaskImpl.java:95)
6 kotlinx.coroutines.scheduling.CoroutineScheduler.void runSafely(kotlinx.coroutines.scheduling.Task)(CoroutineScheduler.java:570)
7 kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.void executeTask(kotlinx.coroutines.scheduling.Task)(CoroutineScheduler.java:750)
8 kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.void runWorker()(CoroutineScheduler.java:677)
9 kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.void run()(CoroutineScheduler.java:664)
panpf commented 1 year ago

非常抱歉啊兄弟,害你测了这么多次。

上次修复时整体架构都改了,协程之间用 Result 封装结果或小范围的异常,不再用 throw 抛异常,走到最后时为了共享 error 处理流程,以及最后做一层保险,就在最后拿到异常后再次抛出,没想到啊还是有遗漏,现在直接处理不再抛了,全程没有一个不受控的 throw 了。

3.2.1-rc03 版本已经发布了,再试最后一次吧!😭

lr555 commented 1 year ago

问题不大,测试多几次也没啥,铁子加油💪🏻

lr555 commented 1 year ago

非常抱歉啊兄弟,害你测了这么多次。

上次修复时整体架构都改了,协程之间用 Result 封装结果或小范围的异常,不再用 throw 抛异常,走到最后时为了共享 error 处理流程,以及最后做一层保险,就在最后拿到异常后再次抛出,没想到啊还是有遗漏,现在直接处理不再抛了,全程没有一个不受控的 throw 了。

3.2.1-rc03 版本已经发布了,再试最后一次吧!😭

还是有这个问题😂,

image image
panpf commented 1 year ago

没道理啊,03 版本根本就不抛异常,怎么还会导致崩溃呢,你测试的时候复现的吗? 你进 QQ 群(529630740)沟通吧,在这儿效率太低了

lr555 commented 1 year ago

不好意思😂,今天测没复现,昨天估计是安装错包了。 今天拿3.2.1-rc02在测试机也复现了,补充一下没有代码混淆的错误日志:

 FATAL EXCEPTION: main
    Process: com.xxx, PID: 24296
    java.io.IOException: HTTP code error. code=401, message=Unauthorized. https://xxx
        at com.github.panpf.sketch.fetch.HttpUriFetcher$executeFetch$2.invokeSuspend(HttpUriFetcher.kt:98)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
        at kotlinx.coroutines.internal.LimitedDispatcher.run(LimitedDispatcher.kt:42)
        at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:95)
        at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)
        Suppressed: kotlinx.coroutines.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@2537004, Dispatchers.Main]