安卓前台服务启动崩溃: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
相关产品推荐
相关产品推荐

