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

Android Kotlin拍照后无法保存至相册问题求助

解决Android拍照后图片无法显示在系统相册的问题

你的代码里图片存在了应用私有外部存储目录(getExternalFilesDir),这个目录的文件不会被系统媒体扫描器自动索引,所以相册看不到。另外你也没有主动通知媒体库更新文件。下面是具体的修复方案:

核心问题分析

  • getExternalFilesDir(Environment.DIRECTORY_PICTURES) 是应用私有目录,系统媒体库不会自动扫描这里的文件
  • Android 10及以上启用了Scoped Storage,直接操作公共目录的File会有兼容问题

修复步骤

  1. 适配存储目录:将图片存到公共图片目录,Android 10+推荐用MediaStore插入
  2. 通知媒体库扫描:Android 9及以下需要主动发送广播让相册识别新文件
  3. 权限适配:动态申请存储权限(仅Android 9及以下需要)

修改后的完整代码

class TomarFotos : AppCompatActivity() {

    val REQUEST_IMAGE_CAPTURE = 1
    private var photoUri: Uri? = null // 替换原photoPath,适配Android 10+

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_tomar_fotos)
        val foto = findViewById<Button>(R.id.tomarfotos)
        foto.setOnClickListener {
            checkPermissionAndTakePhoto()
        }
    }

    private fun checkPermissionAndTakePhoto() {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
            if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), 100)
                return
            }
        }
        tomarFoto()
    }

    fun tomarFoto() {
        val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
        if (intent.resolveActivity(packageManager) != null) {
            photoUri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                // Android 10+ 使用MediaStore创建公共目录Uri,自动加入媒体库
                val contentValues = ContentValues().apply {
                    put(MediaStore.Images.Media.DISPLAY_NAME, "foto_${System.currentTimeMillis()}.jpg")
                    put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
                    put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES)
                }
                contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
            } else {
                // Android 9及以下用FileProvider获取Uri
                val photoFile = createImageFile()
                photoFile?.let {
                    FileProvider.getUriForFile(this, "com.example.android.fileprovider", it)
                }
            }

            photoUri?.let {
                intent.putExtra(MediaStore.EXTRA_OUTPUT, it)
                startActivityForResult(intent, REQUEST_IMAGE_CAPTURE)
            }
        }
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        val fotoTomada = findViewById<ImageView>(R.id.fotopreview)
        if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
            fotoTomada.rotation = 90f
            fotoTomada.setImageURI(photoUri)

            // Android 9及以下需要通知媒体库扫描文件
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
                photoUri?.let { uri ->
                    val mediaScanIntent = Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE)
                    mediaScanIntent.data = uri
                    sendBroadcast(mediaScanIntent)
                }
            }
        }
    }

    private fun createImageFile(): File? {
        val fileName = "foto_${System.currentTimeMillis()}"
        val storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
        if (!storageDir.exists()) storageDir.mkdirs()
        return File(storageDir, "$fileName.jpg")
    }

    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if (requestCode == 100 && grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            tomarFoto()
        }
    }
}

额外配置

在AndroidManifest.xml中添加权限和FileProvider配置:

<!-- 权限配置 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" />
<uses-feature android:name="android.hardware.camera" android:required="true" />

<!-- FileProvider配置(Android 9及以下需要) -->
<application ...>
    <provider
        android:name="androidx.core.content.FileProvider"
        android:authorities="com.example.android.fileprovider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_paths" />
    </provider>
</application>

在res/xml目录下创建file_paths.xml文件:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="my_images" path="Pictures" />
</paths>

这样修改后,拍照的图片会保存到系统公共图片目录,并且能直接在相册中看到。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 09:50:32