You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jetpack Compose中painterResource崩溃,如何捕获异常避免应用崩溃?

问题描述

我的应用收到Crashlytics报告,部分用户遇到如下崩溃:

Fatal Exception: java.lang.IllegalArgumentException
Only VectorDrawables and rasterized asset types are supported ex. PNG, JPG

此前我偶尔遇到该Compose相关问题,但近期出现频率升高。该问题似乎是Compose的Bug,影响随机用户,且涉及的Drawable并不固定。

我希望能捕获painterResource的异常以避免应用崩溃,为此编写了如下Image Composable,但Composable中不允许使用try/catch:

@Composable
fun AppImage(
    modifier: Modifier = Modifier,
    @DrawableRes resource: Int,
    colorFilter: ColorFilter? = null
) {
    Image(
        modifier = modifier,
        painter = painterResource(id = resource),
        contentDescription = null,
        colorFilter = colorFilter
    )
}

请问有什么可行的解决方案?


解决方案

方案一:用produceState异步加载并捕获异常

produceState支持在后台执行加载逻辑并处理异常,适合Compose中的状态管理场景:

@Composable
fun AppImage(
    modifier: Modifier = Modifier,
    @DrawableRes resource: Int,
    colorFilter: ColorFilter? = null,
    placeholderPainter: Painter = painterResource(R.drawable.default_placeholder) // 替换为你的占位图资源
) {
    val painterState = produceState<Painter?>(null, resource) {
        value = try {
            painterResource(resource)
        } catch (e: IllegalArgumentException) {
            // 捕获目标异常,返回占位图
            placeholderPainter
        } catch (e: Exception) {
            // 兜底处理其他未知异常
            placeholderPainter
        }
    }

    painterState.value?.let { painter ->
        Image(
            modifier = modifier,
            painter = painter,
            contentDescription = null,
            colorFilter = colorFilter
        )
    } ?: run {
        // 加载失败且无占位图时,显示空白容器
        Box(modifier = modifier)
    }
}

方案二:将加载逻辑移到非Composable工具类

把Drawable加载逻辑放到非Composable环境中执行,捕获异常后再在Composable中用remember缓存结果:

// 非Composable工具类,处理Drawable加载逻辑
object PainterLoader {
    fun loadPainter(context: Context, @DrawableRes resId: Int): Painter? {
        return try {
            ContextCompat.getDrawable(context, resId)?.let { drawable ->
                DrawablePainter(drawable)
            }
        } catch (e: Exception) {
            null
        }
    }
}

// 你的自定义Image Composable
@Composable
fun AppImage(
    modifier: Modifier = Modifier,
    @DrawableRes resource: Int,
    colorFilter: ColorFilter? = null,
    placeholderPainter: Painter = painterResource(R.drawable.default_placeholder)
) {
    val context = LocalContext.current
    val painter = remember(resource) {
        PainterLoader.loadPainter(context, resource) ?: placeholderPainter
    }

    Image(
        modifier = modifier,
        painter = painter,
        contentDescription = null,
        colorFilter = colorFilter
    )
}

方案三:用Coil的AsyncImage替代(已集成Coil的项目)

如果项目已经使用Coil图片加载库,AsyncImage自带异常处理机制,支持加载本地资源,无需手动捕获异常:

@Composable
fun AppImage(
    modifier: Modifier = Modifier,
    @DrawableRes resource: Int,
    colorFilter: ColorFilter? = null,
    placeholderPainter: Painter = painterResource(R.drawable.default_placeholder)
) {
    AsyncImage(
        model = ResourceDrawableId(resource),
        contentDescription = null,
        modifier = modifier,
        colorFilter = colorFilter,
        placeholder = placeholderPainter,
        error = placeholderPainter
    )
}

额外建议

  • 排查资源文件:虽然问题随机,但可能存在部分VectorDrawable在特定设备上解析异常,检查资源XML是否符合规范,可为旧设备提供位图资源降级。
  • 异常上报:捕获异常后,通过Crashlytics记录异常信息及对应的资源ID,帮助后续定位是否有特定资源的问题。

内容的提问来源于stack exchange,提问作者alfietap

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 23:57:21