安卓批量重命名App点击按钮崩溃问题求助(附堆栈与代码)
解决批量重命名App的点击崩溃问题
从你提供的崩溃堆栈和代码来看,崩溃的直接原因是数组索引越界,而且你的Service代码里还藏着一个同样的潜在问题,我来一步步帮你解决:
1. 定位点击事件的崩溃根源
崩溃日志明确指向:
java.lang.IndexOutOfBoundsException: Invalid index 2, size is 2 at com.pride.msgshareapp.RenameOption$onCreate$5.onClick(RenameOption.kt:80)
这说明你在点击事件里,尝试访问一个size为2的列表的索引2(而列表的有效索引仅为0和1)。看你的循环代码:
for(i in 0..cc) { reptxt = reptxt.replace("%title",seltitle[i],true) // ... }
Kotlin里的0..cc是闭区间循环,也就是说循环会包含cc这个值。假设cc等于你选中的文件数量(比如2),那么i会取0、1、2三个值,当i=2时,访问seltitle[2]自然就会越界。
修复点击事件的循环
把闭区间的0..cc改成左闭右开的0 until cc,这样循环只会取0到cc-1的数值,刚好对应列表的有效索引。另外我还加了两个细节优化:
renamebtn.setOnClickListener { val paramtxt = paratxt.text.toString().trim() var reptxt = paramtxt // 先做安全检查:确保数据长度匹配,避免后续出错 if (seltitle.size != cc || selalbum.size != cc || selartist.size != cc) { Toast.makeText(this, "数据异常,请重新选择文件", Toast.LENGTH_SHORT).show() return@setOnClickListener } // 用until代替..,彻底避免索引越界 for(i in 0 until cc) { reptxt = paramtxt // 重置为原始模板,避免循环中累积替换导致文件名出错 reptxt = reptxt.replace("%title",seltitle[i],true) reptxt = reptxt.replace("%album",selalbum[i],true) reptxt = reptxt.replace("%artist",selartist[i],true) resultt.add(reptxt) } val inte = Intent(this,RenameService::class.java) inte.putExtra("path",selpath.toTypedArray()) inte.putExtra("newname",resultt.toTypedArray()) if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { startForegroundService(inte) } else{ startService(inte) } }
2. 修复Service里的潜在崩溃
你的Service代码里也有一模一样的索引越界问题,同时进度计算也不符合用户认知:
for(i in 0..pathss.size) { if(renameTarget(pathss[i],namess[i])!=0) { // ... } }
pathss.size是文件的数量,比如有2个文件,size是2,0..2会让i取0、1、2,访问pathss[2]就会越界;而且处理完第0个文件后进度显示为0,用户会误以为还没开始处理。
修复Service的循环和进度逻辑
with(NotificationManagerCompat.from(this)){ builderr.setProgress(maxProgress, currentProgress, false) notify(notifID, builderr.build()) // 安全检查:确保路径和新文件名数量匹配 if (pathss.size != namess.size) { builderr.setContentText("重命名失败:文件名与路径数量不匹配") .setProgress(0,0,false) .setAutoCancel(true) notify(notifID, builderr.build()) stopSelf() return@with } // 用indices遍历,Kotlin推荐的安全遍历数组索引的方式 for(i in pathss.indices) { if(renameTarget(pathss[i],namess[i])!=0) { resultt.add("Failed") } else { resultt.add("Success") } currentProgress = i + 1 // 进度从1开始计数,符合用户对"已完成数量"的认知 builderr.setContentText("Renaming ${currentProgress} of ${pathss.size}") builderr.setProgress(maxProgress,currentProgress,false) notify(notifID,builderr.build()) } builderr.setContentText("Rename Complete") .setProgress(0,0,false) .setContentIntent(pendingIntent) .setAutoCancel(true) notify(notifID,builderr.build()) }
3. 额外的健壮性优化
在renameTarget函数里,获取文件扩展名的逻辑可以更健壮,避免文件没有扩展名时出现异常:
fun renameTarget(filePath:String, newName:String):Int{ val src= File(filePath) if(!src.exists()) { return -2 // 新增文件不存在的错误码 } if(newName.isEmpty()) { return -1 } val ext = if(src.isFile) { val lastDotIndex = filePath.lastIndexOf(".") // 处理没有扩展名的文件 if(lastDotIndex != -1) filePath.substring(lastDotIndex) else "" } else { "" } val temp = filePath.substring(0,filePath.lastIndexOf("/")) val dest= File("$temp/$newName$ext") return if(src.renameTo(dest)) { 0 } else { 1 } }
内容的提问来源于stack exchange,提问作者Grim
相关产品推荐
相关产品推荐

