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

Kotlin如何实现单按钮选图后自动上传至Firebase Storage

问题原因

你的代码出现选图后需要二次点击才上传的核心问题是执行顺序错误:

  1. 图库选图是异步跳转流程,调用activityResultLauncher.launch(intentToGallery)之后,代码会继续往下执行,不会等待用户选完图再运行后续逻辑
  2. 你把Firebase Storage上传逻辑直接写在了按钮的长按回调里,第一次触发按钮时,刚拉起图库,selectedPicture变量还是空值,上传的非空判断直接跳过
  3. 等用户选完图回到页面,selectedPicture才会在activityResultLauncher的结果回调里被赋值,这时候上传逻辑早就执行完毕,只有第二次长按按钮的时候,selectedPicture已经存了上一次选中的图片Uri,才会触发上传操作。
修复方案
  • 把所有上传相关逻辑从按钮长按回调中抽离,封装成独立的上传方法
  • 在选图结果回调中,拿到选中的图片Uri后直接调用上传方法,实现选完即传的连贯流程
  • 补充Android版本权限适配,Android 13(API 33)及以上版本读取图库图片需要使用READ_MEDIA_IMAGES权限,旧的READ_EXTERNAL_STORAGE权限在高版本系统上会失效
  • 补充上传失败的回调逻辑,方便排查异常场景
修复后代码示例

1. 按钮长按事件(仅保留权限校验、拉起图库逻辑)

idgir.setOnLongClickListener {
    // 分版本做权限校验
    val requiredPermission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        Manifest.permission.READ_MEDIA_IMAGES
    } else {
        Manifest.permission.READ_EXTERNAL_STORAGE
    }

    if (ContextCompat.checkSelfPermission(this, requiredPermission) != PackageManager.PERMISSION_GRANTED) {
        if (ActivityCompat.shouldShowRequestPermissionRationale(this, requiredPermission)) {
            Snackbar.make(
                binding.root,
                "需要图库权限才能选择图片",
                Snackbar.LENGTH_INDEFINITE
            ).setAction("授予权限") {
                permissionLauncher.launch(requiredPermission)
            }.show()
        } else {
            permissionLauncher.launch(requiredPermission)
        }
    } else {
        val intentToGallery = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
        activityResultLauncher.launch(intentToGallery)
    }
    // 消费长按事件,避免触发其他默认逻辑
    return@setOnLongClickListener true
}

2. 注册结果启动器(选图成功后直接触发上传)

private fun registerLauncher() {
    activityResultLauncher =
        registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
            if (result.resultCode == RESULT_OK) {
                val intentFromResult = result.data
                if (intentFromResult != null) {
                    val selectedPicture = intentFromResult.data
                    selectedPicture?.let {
                        binding.idgir.setImageURI(it)
                        // 选到图片后直接调用上传方法,无需二次点击
                        uploadImageToFirebase(it)
                    }
                }
            }
        }

    permissionLauncher =
        registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
            if (isGranted) {
                val intentToGallery = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
                activityResultLauncher.launch(intentToGallery)
            } else {
                Toast.makeText(this@MainActivity, "需要授予图库权限才能选择图片", Toast.LENGTH_LONG).show()
            }
        }
}

3. 抽离独立的Firebase上传方法

private fun uploadImageToFirebase(imageUri: Uri) {
    val uuid = UUID.randomUUID()
    val imageName = "$uuid.jpg"

    val reference = storage.reference
    val imageReference = reference.child("images").child(imageName)

    imageReference.putFile(imageUri)
        .addOnSuccessListener {
            // 上传文件成功后获取可访问的下载链接
            val uploadPictureReference = storage.reference.child("images").child(imageName)
            uploadPictureReference.downloadUrl.addOnSuccessListener { downloadUri ->
                // 此处可添加后续业务逻辑,比如将下载链接存入数据库、更新UI等
                Toast.makeText(this@MainActivity, "图片上传成功", Toast.LENGTH_SHORT).show()
            }
        }
        .addOnFailureListener { e ->
            // 处理上传失败场景
            Toast.makeText(this@MainActivity, "图片上传失败:${e.message}", Toast.LENGTH_SHORT).show()
        }
}
额外配置说明
  • 需要在AndroidManifest.xml中补充对应权限声明,兼容高低版本系统:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
  • 确保Firebase Storage规则配置正确,测试阶段可临时设置为允许认证用户读写,上线前记得调整为符合业务安全要求的规则。

内容的提问来源于stack exchange,提问作者terlan abaszade

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 13:36:17