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

Android应用首次授予存储权限时崩溃后续下载正常怎么解决?

问题原因

崩溃的根因是权限申请通过的回调中传入了空列表执行下载逻辑:
从堆栈信息可以看到IndexOutOfBoundsException: Index: 11, Size: 0,说明你尝试在大小为0的列表中取索引为11的元素,触发越界异常。

你在点击下载按钮时,如果检测到没有存储权限会触发权限申请,但是权限申请通过后,onRequestPermissionsResult回调里调用startDownloading时传的是ArrayList < ImageModel > ()——这是一个全新的空列表,而此时ViewPager的当前位置是11,空列表不存在对应索引的元素,直接触发崩溃。
后续操作正常是因为首次授权完成后,再次点击下载按钮不会走权限申请逻辑,直接传入有数据的全局列表执行下载,所以不会报错。

修复方案

最简修复

如果你页面的图片列表list是Activity的全局成员变量,直接修改onRequestPermissionsResult中的调用逻辑即可:

override fun onRequestPermissionsResult(requestCode:Int, permissions:Array<out String>, grantResults: IntArray){
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    when(requestCode) {
        STORAGE_PERMISSION_CODE -> {
            if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // 替换为空列表的调用,传入全局有数据的列表
                startDownloading(list)
            } else {
                Toast.makeText(this, "Permission denied", Toast.LENGTH_SHORT).show()
            }
        }
    }
}

优化方案(更稳定)

如果担心用户在申请权限的过程中滑动了ViewPager,导致权限通过后下载的不是用户之前点击的图片,可以额外新增成员变量存储待下载的目标图片:

  1. 新增全局成员变量存储待下载的图片数据
private var pendingDownloadModel: ImageModel? = null
  1. 点击下载按钮申请权限前,先存储当前要下载的图片
downloadBtn.setOnClickListener {
    val currentModel = list[viewPager.currentItem]
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) {
            // 先存下待下载的图片
            pendingDownloadModel = currentModel
            ActivityCompat.requestPermissions(
                    this, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
                    STORAGE_PERMISSION_CODE
            )
        } else {
            startDownloading(currentModel)
        }
    } else {
        startDownloading(currentModel)
    }
}
  1. 修改startDownloading入参,直接接收单个图片模型,不需要传整个列表
private fun startDownloading(model: ImageModel){
    Toast.makeText(this, "Downloading", Toast.LENGTH_SHORT).show()
    val downloadUrl = model.urls.full
    val request = DownloadManager.Request(Uri.parse(downloadUrl))
            .setDestinationInExternalPublicDir(
                    Environment.DIRECTORY_PICTURES, "/unsplash/${model.id}.jpg"
            )
            .setTitle("Downloading").setDescription("downloading image").setAllowedOverMetered(true)
            .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
    val manager = getSystemService(DOWNLOAD_SERVICE) as DownloadManager
    myId = manager.enqueue(request)
    val br = object :BroadcastReceiver() {
        override fun onReceive(context:Context?, intent:Intent?){
            val id = intent?.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1)
            if (id == myId) {
                Toast.makeText(
                        this@ViewPagerActivity,
                        "Downloaded Successfully",
                        Toast.LENGTH_SHORT
                ).show()
            }
        }
    }
    registerReceiver(br, IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE))
}
  1. 权限通过后直接用预存的图片执行下载
override fun onRequestPermissionsResult(requestCode:Int, permissions:Array<out String>, grantResults: IntArray){
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    when(requestCode) {
        STORAGE_PERMISSION_CODE -> {
            if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                pendingDownloadModel?.let { startDownloading(it) }
                pendingDownloadModel = null
            } else {
                Toast.makeText(this, "Permission denied", Toast.LENGTH_SHORT).show()
                pendingDownloadModel = null
            }
        }
    }
}
额外注意事项
  • 你当前代码中动态注册的下载完成广播没有解绑逻辑,需要在Activity销毁时调用unregisterReceiver,避免内存泄漏。
  • 如果你的应用要适配Android 13(API 33)及以上版本,WRITE_EXTERNAL_STORAGE权限已经废弃,需要根据你的业务场景替换为对应的图片/视频/文件权限。

内容的提问来源于stack exchange,提问作者Muaz Khan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 14:15:07