MediaScannerConnection.scanFile() 返回空 uri
MediaScannerConnection.scanFile() returning null uri
我正在尝试将文件另存为 canvas 的 PNG,用户可以在其中绘制内容,然后调用 Intent.ACTION_SEND
,以便用户可以与其他应用分享它的绘图。
代码能够毫无问题地保存文件,但是当我尝试使用 MediaScannerConnection.scanFile()
时,函数编辑的 Uri
return 是 null
.我使用的是创建文件的绝对路径,所以我不明白为什么会这样。
我的 class,称为 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
}
** mBitmap
变量只是从 canvas.
生成的位图
在这里,Log.d
returns,例如:
D/File: /storage/emulated/0/Android/data/com.example.kidsdrawingapp/cache/KidsDrawingApp_1599992654.png
如果我打开 Files
应用程序并搜索它,我可以很好地访问该文件。
但是当我 运行 MediaScannerConnection
on onPostExecute()
时,该函数根本不会 return 基于绝对路径的 uri。这是代码:
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"
)
)
}
再一次,Log.d("Path", path)
return 与之前的 Log.d()
是同一个文件,但是当我尝试将 Uri
转换为字符串时,它崩溃了,因为它是空的。
我尝试添加 "file://" + file.absolutePath"
就像我在其他一些答案中看到的那样,但它仍然没有用,由 scanFile()
编辑的 uri
return 仍然为空.
我正在使用 API 21.
文件提供商代码
AndroidManifest.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>
@xml/path.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="captured" path="Android/data/com.example.kidsdrawingapp/files" />
</paths>
I can't seem to figure out why it can't return a valid uri if the file is being saved in the phone and the path is a valid one
有效。但是,在 Android 10 及更高版本上,MediaStore
无法对其进行索引。 MediaStore
将不再索引 app-specific 外部存储中的文件,例如 getExternalFilesDir()
,这是您正在使用的。
如果您的 objective 是让图像可供设备上的每个应用程序使用,那么被 MediaStore
索引就可以了。在 Android 10+ 上,您可以 insert()
进入 MediaStore
并使用生成的 Uri
来写出您的内容。请参阅 this sample app 进行演示,但就我而言,我正在编写视频,而不是 PNG。
如果您只想分享此内容,请不要使用 MediaScannerConnection
。相反,使用 FileProvider
。请参阅 the documentation and this sample app(尽管就我而言,我共享的是 PDF,而不是 PNG)。
...如果上面的解决方案不是每个人都清楚 - 这是我如何将建议的修复程序应用到教程练习“Kids Drawing App”(来自“The Complete Android Udemy 的 10 和 Kotlin 开发大师班):
// offer to share content
MediaScannerConnection.scanFile(
this@MainActivity,
arrayOf(result),
null
) { path, _ ->
// Use the FileProvider to get a content URI
val requestFile = File(path)
val fileUri: Uri? = try {
FileProvider.getUriForFile(
this@MainActivity,
AUTHORITY,
requestFile)
} catch (e: IllegalArgumentException) {
Log.e("File Selector",
"The selected file can't be shared: $requestFile")
null
}
val shareIntent = Intent()
shareIntent.action = Intent.ACTION_SEND
shareIntent.type = "image/png"
shareIntent.putExtra(Intent.EXTRA_STREAM, fileUri)
startActivity(
Intent.createChooser(
shareIntent, "Share"
)
)
}
... 我在其中添加了以下 AUTHORITY 定义:
// static variables
companion object {
private const val STORAGE_PERMISSION_CODE = 1
private const val GALLERY = 2
private const val AUTHORITY = "${BuildConfig.APPLICATION_ID}.fileprovider"
}
我正在尝试将文件另存为 canvas 的 PNG,用户可以在其中绘制内容,然后调用 Intent.ACTION_SEND
,以便用户可以与其他应用分享它的绘图。
代码能够毫无问题地保存文件,但是当我尝试使用 MediaScannerConnection.scanFile()
时,函数编辑的 Uri
return 是 null
.我使用的是创建文件的绝对路径,所以我不明白为什么会这样。
我的 class,称为 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
}
** mBitmap
变量只是从 canvas.
在这里,Log.d
returns,例如:
D/File: /storage/emulated/0/Android/data/com.example.kidsdrawingapp/cache/KidsDrawingApp_1599992654.png
如果我打开 Files
应用程序并搜索它,我可以很好地访问该文件。
但是当我 运行 MediaScannerConnection
on onPostExecute()
时,该函数根本不会 return 基于绝对路径的 uri。这是代码:
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"
)
)
}
再一次,Log.d("Path", path)
return 与之前的 Log.d()
是同一个文件,但是当我尝试将 Uri
转换为字符串时,它崩溃了,因为它是空的。
我尝试添加 "file://" + file.absolutePath"
就像我在其他一些答案中看到的那样,但它仍然没有用,由 scanFile()
编辑的 uri
return 仍然为空.
我正在使用 API 21.
文件提供商代码
AndroidManifest.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>
@xml/path.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="captured" path="Android/data/com.example.kidsdrawingapp/files" />
</paths>
I can't seem to figure out why it can't return a valid uri if the file is being saved in the phone and the path is a valid one
有效。但是,在 Android 10 及更高版本上,MediaStore
无法对其进行索引。 MediaStore
将不再索引 app-specific 外部存储中的文件,例如 getExternalFilesDir()
,这是您正在使用的。
如果您的 objective 是让图像可供设备上的每个应用程序使用,那么被 MediaStore
索引就可以了。在 Android 10+ 上,您可以 insert()
进入 MediaStore
并使用生成的 Uri
来写出您的内容。请参阅 this sample app 进行演示,但就我而言,我正在编写视频,而不是 PNG。
如果您只想分享此内容,请不要使用 MediaScannerConnection
。相反,使用 FileProvider
。请参阅 the documentation and this sample app(尽管就我而言,我共享的是 PDF,而不是 PNG)。
...如果上面的解决方案不是每个人都清楚 - 这是我如何将建议的修复程序应用到教程练习“Kids Drawing App”(来自“The Complete Android Udemy 的 10 和 Kotlin 开发大师班):
// offer to share content
MediaScannerConnection.scanFile(
this@MainActivity,
arrayOf(result),
null
) { path, _ ->
// Use the FileProvider to get a content URI
val requestFile = File(path)
val fileUri: Uri? = try {
FileProvider.getUriForFile(
this@MainActivity,
AUTHORITY,
requestFile)
} catch (e: IllegalArgumentException) {
Log.e("File Selector",
"The selected file can't be shared: $requestFile")
null
}
val shareIntent = Intent()
shareIntent.action = Intent.ACTION_SEND
shareIntent.type = "image/png"
shareIntent.putExtra(Intent.EXTRA_STREAM, fileUri)
startActivity(
Intent.createChooser(
shareIntent, "Share"
)
)
}
... 我在其中添加了以下 AUTHORITY 定义:
// static variables
companion object {
private const val STORAGE_PERMISSION_CODE = 1
private const val GALLERY = 2
private const val AUTHORITY = "${BuildConfig.APPLICATION_ID}.fileprovider"
}