Caused by: java.lang.StringIndexOutOfBoundsException: length=5; regionStart=0; regionLength=-1

本文记录了一次因字符串操作不当导致的StringIndexOutOfBoundsException异常处理过程。问题出现在从数据库获取的数据上,由于单位不统一(克和毫升),导致了字符串截取错误。通过调整代码逻辑并检查数据库数据的一致性解决了该问题。
Caused by: java.lang.StringIndexOutOfBoundsException: length=5;regionStart=0; regionLength=-1
原因:在截取字符串时,取到了负值:String temp_m = c_mount.substring(0,w);
提示的信息是,这个字符串c_mount的长度是5,从0开始,取到了-1,所以报错了。


应该查找的地方是w,后来发现int w=c_mount.lastIndexOf(getText


(R.string.gram).toString());
分析了一下,发现c_mount是从数据库中取出来的,很可能是数据库中的数据的问题


,打开数据库,查看,发现果然,这个字段不全是相同的单位,有克,有毫升,所以


,分开对待就好了。问题解决。
<think>我们遇到了一个ArrayIndexOutOfBoundsException异常,异常信息为: src.length=279936 srcPos=0 dst.length=279936 dstPos=0 length=2985984 这个异常发生在使用System.arraycopy方法时。根据异常信息,我们可以知道: - 源数组(src)的长度为279936 - 目标数组(dst)的长度为279936 - 尝试复制的数据长度(length)为2985984 显然,复制的长度(length)超过了源数组和目标数组的长度(279936),因此抛出了数组越界异常。 ### 原因分析: 在调用System.arraycopy方法时,需要确保以下条件满足: srcPos + length <= src.length dstPos + length <= dst.length 这里,由于length=2985984大于src.length(279936)和dst.length(279936),所以必然抛出异常。 ### 解决方法: 我们需要检查复制操作中使用的参数,特别是: 1. 源数组和目标数组的长度是否正确。 2. 复制的长度(length)是否计算正确,是否超过了数组的实际长度。 在之前的代码中,我们有一个方法`NV21ToNV12`,其中使用了System.arraycopy。回顾该方法,我们复制的是Y分量(亮度分量),长度应该是`framesize`(即width*height)。而色度部分的大小为`framesize/2`(因为4:2:0采样,色度数据是亮度数据的1/2)。 根据异常信息,源数组和目标数组的长度都是279936,而尝试复制的长度却是2985984,这明显是不合理的。因此,我们需要检查传入的width和height的值,以及计算framesize的代码。 假设我们传入的width和height分别为: width = 宽度 height = 高度 则framesize = width * height 在异常信息中,源数组长度为279936,所以framesize应该是279936(因为System.arraycopy复制的是Y分量,长度为framesize)。但是,我们尝试复制的长度却是2985984,这个值远远大于framesize,说明在调用System.arraycopy时传入的length参数有误。 ### 修正步骤: 1. 检查调用System.arraycopy的代码,确保length参数是framesize(即width*height),而不是其他值。 2. 检查传入的width和height是否与图像的实际尺寸一致,以及是否在计算framesize后,确保framesize不超过数组的长度。 ### 示例代码修正: 在之前的`NV21ToNV12`方法中,我们使用: System.arraycopy(nv21, 0, nv12, 0, framesize); 这里,framesize应该等于width*height。如果传入的width和height的乘积不等于数组应有的长度,那么就会出错。 此外,我们还需要确保整个数组的长度足够: - nv21数组长度至少为:framesize + framesize/2 (因为Y分量占framesize,UV分量占framesize/2,总共1.5*framesize) - nv12数组也需要同样的长度。 ### 验证数组长度: 在调用`NV21ToNV12`之前,应该检查传入的数组长度是否正确。例如,对于NV21格式,数组长度应为:width * height * 3 / 2(即1.5倍的帧大小)。如果数组长度不满足,那么调用该方法就会导致越界。 ### 建议的修复代码: 在方法开始时添加对数组长度的检查: ```java private void NV21ToNV12(byte[] nv21, byte[] nv12, int width, int height) { if (nv21 == null || nv12 == null) return; int framesize = width * height; // 检查数组长度是否满足要求 if (nv21.length < framesize * 3 / 2) { throw new IllegalArgumentException("nv21 array length is too small: " + nv21.length); } if (nv12.length < framesize * 3 / 2) { throw new IllegalArgumentException("nv12 array length is too small: " + nv12.length); } // 复制Y分量 System.arraycopy(nv21, 0, nv12, 0, framesize); // 转换UV:NV21的UV是VU交替,NV12的UV是UV交替,所以要交换U和V for (int i = framesize; i < framesize + framesize / 2; i += 2) { // 在NV21中,色度数据的偶数索引是V,奇数索引是U byte v = nv21[i]; byte u = nv21[i + 1]; // 在NV12中,色度数据的偶数索引是U,奇数索引是V nv12[i] = u; nv12[i + 1] = v; } } ``` ### 异常分析: 在提供的异常信息中,复制的长度2985984可能是由于framesize计算错误导致的。例如,如果width和height是图像的尺寸,那么framesize应该是width*height。但是,如果错误地将framesize乘以了某个系数(比如乘以了12,因为一些格式如YUV420有3个平面?),就会导致framesize变得非常大。 ### 可能的原因: 1. 传入的width和height并不是图像的实际宽高,而是包含了一些额外的信息(比如stride宽度,即内存对齐后的宽度,可能比实际宽度大)。 2. 计算framesize时,错误地使用了width * height * 某个倍数。 ### 解决方案: 如果图像数据带有stride(步长),那么Y分量的实际存储长度是stride * height,而不是width * height。因此,需要根据实际情况调整。 在调用该方法时,确保传入的width和height是图像的实际宽度和高度,并且图像数据是紧密排列的(没有stride)。如果存在stride,则需要使用stride作为Y分量的行宽,此时复制Y分量需要逐行复制,并且只复制有效宽度(width)部分。 ### 结论: ArrayIndexOutOfBoundsException是由于复制的长度超过了数组的实际长度。我们需要确保在调用System.arraycopy时,复制的长度不超过源数组和目标数组的长度。另外,要检查传入的width和height的值是否正确,以及数组是否满足NV21/NV12格式的长度要求(1.5 * width * height)。 §§相关问题§§: 1.Java中,System.arraycopy方法的使用注意事项有哪些? 2. 如何处理图像数据转换时可能出现的数组越界问题? 3. 在Android开发中,NV21和NV12格式有什么应用场景? 4. 如何正确计算YUV420格式图像数据的内存大小? </think>### 问题分析:`ArrayIndexOutOfBoundsException` **根本原因**: 当调用 `System.arraycopy()` 方法时,指定的复制长度 `length=2,985,984` 超过了源数组或目标数组的实际长度(两个数组长度均为 279,936)。这违反了 `System.arraycopy()` 的基本前提条件: ```java srcPos + length <= src.length dstPos + length <= dst.length ``` ### 深度解析: 1. **数组长度计算错误** - NV21/NV12 格式的图像数据总长度应为: `width * height * 3 / 2`(Y分量占1倍,UV分量占0.5倍) - 您的输入参数: - `src.length = dst.length = 279,936` - 实际需要的复制长度:`2,985,984`(约10.67倍于数组长度) - **矛盾点**:计算得出的 `framesize = width * height` 与数组长度不匹配 2. **典型场景还原**: 假设图像分辨率是 864×324: ```java int width = 864; int height = 324; int framesize = width * height; // 864 * 324 = 279,936 int totalSize = framesize * 3 / 2; // 419,904 (实际需要) ``` - 但您尝试复制的长度 2,985,984 ≈ 279,936 × 10.67 - 证明 `width` 或 `height` 被错误放大了约 √10.67 ≈ 3.26 倍 ### 解决方案: #### 步骤1:验证输入参数 ```java // 添加参数校验逻辑 private void safeNV21ToNV12(byte[] nv21, byte[] nv12, int width, int height) { // 1. 基础空指针检查 if (nv21 == null || nv12 == null) { throw new IllegalArgumentException("输入数组不能为null"); } // 2. 计算理论长度 int frameSize = width * height; int expectedTotalSize = frameSize * 3 / 2; // YUV420的总长度 // 3. 验证数组实际长度 if (nv21.length < expectedTotalSize) { throw new IllegalArgumentException( "nv21数组长度不足: 需要=" + expectedTotalSize + " 实际=" + nv21.length ); } if (nv12.length < expectedTotalSize) { throw new IllegalArgumentException( "nv12数组长度不足: 需要=" + expectedTotalSize + " 实际=" + nv12.length ); } // 4. 执行安全转换 (原修正后的转换逻辑) doNV21ToNV12(nv21, nv12, width, height); } ``` #### 步骤2:安全转换实现 ```java private void doNV21ToNV12(byte[] nv21, byte[] nv12, int width, int height) { int frameSize = width * height; // 1. 复制Y分量 (亮度) System.arraycopy(nv21, 0, nv12, 0, frameSize); // 2. 处理UV分量 int uvStart = frameSize; // UV数据起始位置 int uvSize = frameSize / 2; // UV数据总长度 for (int i = 0; i < uvSize; i += 2) { // NV21: [V0, U0, V1, U1, ...] // NV12: [U0, V0, U1, V1, ...] byte v = nv21[uvStart + i]; // 取V分量 byte u = nv21[uvStart + i + 1]; // 取U分量 nv12[uvStart + i] = u; // 写入U分量 nv12[uvStart + i + 1] = v; // 写入V分量 } } ``` ### 关键预防措施: 1. **调用前参数校验** 检查传入的 `width` 和 `height` 是否来自可信源: ```java // 示例:从Camera回调获取数据时 @Override public void onPreviewFrame(byte[] data, Camera camera) { Camera.Size size = camera.getParameters().getPreviewSize(); int width = size.width; // 直接使用相机提供的尺寸 int height = size.height; // 创建符合长度的缓冲区 byte[] output = new byte[width * height * 3 / 2]; safeNV21ToNV12(data, output, width, height); } ``` 2. **常见错误场景** - 错误使用 `stride`(内存对齐宽度)代替实际 `width` - 图像旋转后未更新宽高参数 - 跨平台传输时宽高序列化错误
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值