MediaScannerConnection.scanFile() 返回 null uri

Dan*_*ldi 7 android android-mediascanner kotlin

我正在尝试将文件另存为画布的PNG文件,用户可以在其中绘制一些内容,然后调用Intent.ACTION_SEND以便用户可以与其他应用程序共享其绘图。

该代码能够毫无问题地保存文件,但是当我尝试使用 时MediaScannerConnection.scanFile()Uri该函数返回的是null. 我使用的是创建文件的绝对路径,所以我无法理解为什么会发生这种情况。

我的类,称为BitmapAsyncTask继承AsyncTask(是的,我知道它已被弃用)。这是重要的代码:

将文件写入内存:

override fun doInBackground(vararg p0: Any?): String {
    var result = ""

    try {
        val bytes = ByteArrayOutputStream()
        mBitmap.compress(Bitmap.CompressFormat.PNG, 95, bytes)
        val file = File(externalCacheDir!!.absoluteFile.toString()
                + File.separator + "KidsDrawingApp_"
                + System.currentTimeMillis() / 1000 + ".png")
        val fileOutput = FileOutputStream(file)
        fileOutput.write(bytes.toByteArray())
        fileOutput.close()
        result = file.absolutePath
    } catch (e: Exception) {
        e.printStackTrace()
    }

    Log.d("File", result)
    return result
}
Run Code Online (Sandbox Code Playgroud)

** 该mBitmap变量只是从画布生成的位图。

这里,Log.d以返回为例:

D/File: /storage/emulated/0/Android/data/com.example.kidsdrawingapp/cache/KidsDrawingApp_1599992654.png
Run Code Online (Sandbox Code Playgroud)

Files如果我打开应用程序并搜索它,我就可以很好地访问该文件。

但是当我运行MediaScannerConnectionon时onPostExecute(),该函数根本不返回基于绝对路径的 uri。这是代码:

D/File: /storage/emulated/0/Android/data/com.example.kidsdrawingapp/cache/KidsDrawingApp_1599992654.png
Run Code Online (Sandbox Code Playgroud)

再次返回Log.d("Path", path)与前一个相同的文件Log.d(),但是当我尝试将其转换Uri为字符串时,它崩溃了,因为它为空。

我尝试添加"file://" + file.absolutePath"像我在其他一些答案中看到的那样,但它仍然不起作用,uri返回的scanFile()仍然为空。

我正在使用 API 21。

文件提供者代码

AndroidManifest.xml

MediaScannerConnection.scanFile(this@MainActivity, arrayOf(result), null) {
    path, uri -> val shareIntent = Intent()
    Log.d("Path", path)
    Log.d("Uri", uri.toString())
    shareIntent.action = Intent.ACTION_SEND
    shareIntent.putExtra(Intent.EXTRA_STREAM, uri)
    shareIntent.type = "image/png"
    startActivity(
        Intent.createChooser(
            shareIntent, "Share image"
        )
    )
}
Run Code Online (Sandbox Code Playgroud)

@xml/path.xml

<provider
    android:name="androidx.core.content.FileProvider"
    android:authorities="com.example.kidsdrawingapp.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true" >

    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/path" />
</provider>
Run Code Online (Sandbox Code Playgroud)

Com*_*are 7

我似乎无法弄清楚为什么如果文件保存在手机中并且路径是有效的,它不能返回有效的 uri

这是有效的。但是,它无法MediaStore在 Android 10 及更高版本上进行索引。MediaStore将不再索引特定于应用程序的外部存储中的文件,例如getExternalFilesDir()您正在使用的 。

如果您的目标是让设备上的每个应用程序都可以使用该图像,那么通过索引进行索引MediaStore就可以了。在 Android 10+ 上,您可以insert()进入MediaStore并使用结果Uri来写出您的内容。请参阅此示例应用程序进行演示,但在我的例子中,我写的是视频,而不是 PNG。

相反,如果您只想分享此内容,则不要使用MediaScannerConnection。相反,使用FileProvider. 请参阅文档此示例应用程序(尽管在我的例子中我共享的是 PDF,而不是 PNG)。