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

安卓前台服务启动崩溃:Bad notification与bad array lengths问题求助

前台服务启动引发"bad array lengths"崩溃的解决方案

问题概述

使用Foreground Service时,Crashlytics捕获到java.lang.RuntimeException: bad array lengths崩溃,堆栈指向Activity恢复过程中WindowManager添加View时的Parcel读取异常。

崩溃堆栈

Fatal Exception: java.lang.RuntimeException: bad array lengths
at android.os.Parcel.readTypedArray(Parcel.java:3157)
at android.view.IWindowSession$Stub$Proxy.addToDisplayAsUser(IWindowSession.java:1557)
at android.view.ViewRootImpl.setView(ViewRootImpl.java:1556)
at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:509)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:133)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:5322)
at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:54)
at android.app.servertransaction.ActivityTransactionItem.execute(ActivityTransactionItem.java:45)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:176)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2438)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:226)
at android.os.Looper.loop(Looper.java:313)
at android.app.ActivityThread.main(ActivityThread.java:8663)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:567)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1135)

启动前台服务的代码

val recordCommand = gson.fromJson(command, RecordCommand::class.java)
val intent = Intent(applicationContext, RecordCommandService::class.java)
intent.putExtra(RecordCommandProcessingBaseI.EXTRAS, recordCommand)
if (!AppUtils.isServiceRunning(this, RecordCommandService::class.java.name)) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        applicationContext.startForegroundService(intent)
    } else {
        applicationContext.startService(intent)
    }
}

data class RecordCommand(
    val duration: String? = "1",
    val id: String
)

解决方案建议

1. 修复RecordCommand的序列化逻辑

Intent传递自定义对象时,必须确保对象实现Parcelable或Serializable接口,否则会导致Parcel数据损坏,引发数组长度异常。修改RecordCommand实现Parcelable:

data class RecordCommand(
    val duration: String? = "1",
    val id: String
) : Parcelable {
    constructor(parcel: Parcel) : this(
        parcel.readString(),
        parcel.readString()!!
    )

    override fun writeToParcel(parcel: Parcel, flags: Int) {
        parcel.writeString(duration)
        parcel.writeString(id)
    }

    override fun describeContents(): Int {
        return 0
    }

    companion object CREATOR : Parcelable.Creator<RecordCommand> {
        override fun createFromParcel(parcel: Parcel): RecordCommand {
            return RecordCommand(parcel)
        }

        override fun newArray(size: Int): Array<RecordCommand?> {
            return arrayOfNulls(size)
        }
    }
}

2. 检查前台服务的startForeground调用

确保服务启动后5秒内调用startForeground,且通知构建无异常:

  • 验证通知图标是否存在(避免使用不存在的资源ID)
  • 若使用RemoteViews自定义通知布局,检查布局中控件的参数是否合法,无异常数组或过大数据
  • 使用NotificationCompat构建通知,保证跨版本兼容性

3. 校验isServiceRunning方法的正确性

该方法若存在误判,会导致重复启动服务引发资源冲突。确保方法正确查询运行中的服务:

fun isServiceRunning(context: Context, serviceClassName: String): Boolean {
    val manager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
    for (service in manager.getRunningServices(Int.MAX_VALUE)) {
        if (serviceClassName == service.service.className) {
            return true
        }
    }
    return false
}

4. 排查数据异常

检查RecordCommand中的字段值是否合法:

  • 避免duration或id为空字符串、过长字符串
  • 确保Gson解析后的对象无字段值异常(如null值处理)

5. 系统版本兼容处理

若崩溃集中在特定Android版本,可针对该版本调整通知构建逻辑,比如避免使用某些在该版本存在bug的API。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 01:43:31