找不到类“android.provider.MediaStore$Downloads”

Mem*_*ber 4 android mediastore kotlin android-multidex

我正在使用鲍雷提供的代码,名称为private fun saveImage如何将位图保存到 android gallery来保存位图

为了解决 Kotlin 中已弃用的问题,我删除了这些行:

 //values.put(MediaStore.Images.Media.DATA, file.absolutePath) 
//context.contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
Run Code Online (Sandbox Code Playgroud)

并添加了这个:

 val contentValues = ContentValues()

 contentValues.put(MediaStore.Images.Media.RELATIVE_PATH, folderName)

 this.applicationContext.contentResolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, contentValues)
Run Code Online (Sandbox Code Playgroud)

然后,我将该函数(在 DidtodayActivity 中)称为:

saveImage(bitmapImg, this.applicationContext)
Run Code Online (Sandbox Code Playgroud)

图像被下载到Phone>Android>Data>com.example.MyApp1>files>MyFiles。我可以在我的设备中看到下载的图像。

但是,由于这一行的运行时错误,活动文件突然关闭(并且直接打开activity_main .xml):

this.applicationContext.contentResolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, contentValues)
Run Code Online (Sandbox Code Playgroud)

原因

java.lang.ClassNotFoundException: Didn't find class "android.provider.MediaStore$Downloads" on path: DexPathList[[zip file "/data/app/com.example.MyApp1-rvQQjSAj4NilLch2h12faQ==/base.apk"],nativeLibraryDirectories=[/data/app/com.example.MyApp1-rvQQjSAj4NilLch2h12faQ==/lib/arm64, /data/app/com.example.MyApp1-rvQQjSAj4NilLch2h12faQ==/base.apk!/lib/arm64-v8a, /system/lib64]]
Run Code Online (Sandbox Code Playgroud)

详细信息:

**Didn't find class "android.provider.MediaStore$Downloads"** on path: DexPathList[[zip file "/data/app/com.example.MyApp1-rvQQjSAj4NilLch2h12faQ==/base.apk"],nativeLibraryDirectories=[/data/app/com.example.MyApp1-rvQQjSAj4NilLch2h12faQ==/lib/arm64, /data/app/com.example.MyApp1-rvQQjSAj4NilLch2h12faQ==/base.apk!/lib/arm64-v8a, /system/lib64]]
Run Code Online (Sandbox Code Playgroud)

解析失败:Landroid/provider/MediaStore$Downloads;

模块级别的build.gradle是:

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'com.google.gms.google-services'

android {
    compileSdkVersion 29
    buildToolsVersion "29.0.2"

    defaultConfig {
        applicationId "com.example.MyApp1"
        minSdkVersion 16
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

        multiDexEnabled true

    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

    aaptOptions{
        noCompress "tflite"
        noCompress "lite"
    }
}
Run Code Online (Sandbox Code Playgroud)

另外,在build.gradle文件的dependency部分添加了以下代码:

 implementation "com.android.support:multidex:2.0.1"
Run Code Online (Sandbox Code Playgroud)

并且,我在清单文件中添加了以下代码:

  android:name="androidx.multidex.MultiDexApplication">
Run Code Online (Sandbox Code Playgroud)

如何解决运行时错误问题?

我尝试过这个;

this.applicationContext.contentResolver.insert( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
Run Code Online (Sandbox Code Playgroud)

而不是这个;

this.applicationContext.contentResolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, contentValues)
Run Code Online (Sandbox Code Playgroud)

但是,它再次因这个运行时错误而崩溃;

java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=203, result=-1, data=Intent { (has extras) }} to 
activity {com.example.MyApp1/com.example.MyApp1.DidtodayActivity}: java.lang.SecurityException: Permission Denial: writing com.android.providers.media.MediaProvider uri 
content://media/external/images/media from pid=3812, uid=10270 
requires android.permission.WRITE_EXTERNAL_STORAGE, or grantUriPermission()
Run Code Online (Sandbox Code Playgroud)

然而,以下代码已经在Manifest文件中;

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Run Code Online (Sandbox Code Playgroud)

那么,除了MediaStore.Downloads之外,还有其他替代方法可以使用吗?

Gor*_*ail 8

首先你至少需要使用targetSdkVersion 29

https://developer.android.com/training/data-storage/shared/media
    
Downloaded files, which are stored in the Download/ directory. On devices that run
Android 10 (API level 29) and higher, these files are stored in the MediaStore. 
Downloads table. **This table isn't available on Android 9 (API level 28) and lower.**
Run Code Online (Sandbox Code Playgroud)

根据文档,此 api 从 Android 10、api 29 开始可用。

在 api 29 以下,您必须使用旧方法将文件保存在“下载”文件夹中,使用Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)

完整的解决方案:

private val FOLDER = "MyFolder"

private fun saveInDownloads(appContext: Context, fromFile: File) {
    val dst = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        saveInDownloadsForQ(appContext, fromFile.name)
    } else {
        //dont forget to check if you have the permission 
        //to WRITE_EXTERNAL_STORAGE, and ask for it if you don't
        saveInDownloadsBelowQ(appContext, fromFile.name)
    }

    dst?.let {
        try {
            val src = FileInputStream(fromFile)
            dst.channel.transferFrom(src.channel, 0, src.channel.size())
            src.close()
            dst.close()
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }
}

private fun saveInDownloadsForQ(appContext: Context, fileName: String): FileOutputStream? {
    val contentValues = ContentValues().apply {
        put(MediaStore.Downloads.DISPLAY_NAME, fileName)
        put(MediaStore.Downloads.MIME_TYPE, "application/pdf")
        put(MediaStore.Downloads.DATE_ADDED, (System.currentTimeMillis() / 1000).toInt())
        put(MediaStore.Downloads.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS + File.separator + FOLDER)
    }

    val resolver = appContext.contentResolver
    val uri = resolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, contentValues)
    return uri?.let {
        resolver.openOutputStream(uri) as FileOutputStream
    }
}

private fun saveInDownloadsBelowQ(appContext: Context, fileName: String): FileOutputStream {
    val path = Environment.getExternalStoragePublicDirectory(
        Environment.DIRECTORY_DOWNLOADS).toString()

    val dir = File(path, FOLDER)
    val dirFlag = dir.mkdirs()

    val file = File(dir, fileName)
    return FileOutputStream(file)
}
Run Code Online (Sandbox Code Playgroud)