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

安卓批量重命名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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 05:17:45