Please use Android&nbs…

本文提供了解决Android项目中遇到的编译合规级别错误的方法,包括清理项目、调整Java编译器配置等步骤。适用于多个项目的解决。

Android requires compiler compliance level 5.0 or 6.0. Found '1.4' instead. Please use Android Tools > Fix Project Properties.

 

ERROR
  Android requires compiler compliance level 5.0. Please fix project properties.错误。 加了好几个项目都如此,相当郁闷,清除、重新构建项目也不行,没办法只好请教GOOGLE大神。非常的幸运找到了解决的办法:
首先清理项目,然后按以下步骤进行:
1. 项目 右键 ->android tools ->Fix Project
2. 如果不可以,检查Project -> Properties->Java Compiler

确认JDK compliance被设置为1.6,并且enable specific seetings

<think> 我们正在处理的是Android Q(API 29)及以上版本中,关于文件存储适配的问题。用户提到了“Pinning被弃用”,这实际上是指Android Q中引入的存储访问框架(Storage Access Framework, SAF)和分区存储(Scoped Storage)的改变。在Android Q之前,开发者可以使用`StorageManager`的`pinFile`方法来固定文件,但在Android Q及更高版本中,这种方法被弃用,推荐使用`File` API的`setLastModified`和`setWritable`等方法,或者使用`DocumentFile`的`truncate`方法。 根据引用[1]和[2],我们知道在Android Q中,对设备唯一标识符的访问也受到了限制。但用户的问题是关于文件固定(Pinning)被弃用后的替代方案,所以我们的重点应放在存储访问上。 参考引用[4],其中提到了一个第三方库uTakePhoto,它简化了相机和相册的调用,包括裁剪和压缩,这间接说明了在Android Q中处理文件(特别是图片)的复杂性增加,需要适配新的存储模式。 在Android Q中,应用默认被限制在沙盒内(分区存储),不能直接访问外部存储中的任意文件。因此,固定文件(Pinning)在分区存储的背景下不再适用。替代方案如下: 1. **使用MediaStore API**:对于图片、视频、音频等媒体文件,使用MediaStore API来访问和修改。 2. **使用存储访问框架(SAF)**:对于非媒体文件,使用SAF让用户选择文件或目录,然后通过`DocumentFile`进行操作。 3. **使用File API(在分区存储禁用时)**:如果应用暂时禁用分区存储(通过`requestLegacyExternalStorage`属性),则可以继续使用File API,但这只是临时方案,因为未来版本会强制分区存储。 对于用户提到的“trim”方法,实际上在`DocumentFile`中有一个`truncate()`方法,可以用来截断文件(即设置文件大小,如果设置的大小小于当前大小,则文件被截断;如果大于,则用0填充)。这可能是替代固定文件的一种方式,但具体取决于使用场景。 具体步骤: ### 1. 启用分区存储(默认行为) 在AndroidManifest.xml中,确保没有禁用分区存储: ```xml <application ... android:requestLegacyExternalStorage="false"> ... </application> ``` ### 2. 使用MediaStore API访问媒体文件 例如,保存一张图片到公共图片目录: ```kotlin val values = ContentValues().apply { put(MediaStore.Images.Media.DISPLAY_NAME, "my_image.jpg") put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg") put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES) } val resolver = context.contentResolver val uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values) uri?.let { resolver.openOutputStream(it).use { outputStream -> // 将图片数据写入outputStream } } ``` ### 3. 使用存储访问框架(SAF)访问任意文件 对于非媒体文件,或者当需要用户选择特定文件或目录时: - 启动一个Intent让用户选择目录: ```kotlin val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE) startActivityForResult(intent, REQUEST_CODE) ``` - 在`onActivityResult`中,使用`DocumentFile`操作文件: ```kotlin override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { if (requestCode == REQUEST_CODE && resultCode == Activity.RESULT_OK) { val treeUri = data?.data treeUri?.let { val pickedDir = DocumentFile.fromTreeUri(this, it) // 创建文件 val file = pickedDir?.createFile("text/plain", "my_file.txt") file?.let { docFile -> context.contentResolver.openOutputStream(docFile.uri).use { outputStream -> outputStream?.write("Hello, World!".toByteArray()) } } } } } ``` ### 4. 使用truncate方法 如果我们有一个`DocumentFile`对象,我们可以使用`truncate`方法来设置文件大小(固定文件大小): ```kotlin // 假设我们有一个DocumentFile对象,代表一个已存在的文件 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { // 使用ContentResolver的openFileDescriptor来打开文件 context.contentResolver.openFileDescriptor(documentFile.uri, "rw").use { pfd -> pfd?.let { // 截断文件到指定大小(例如100字节) it.fileDescriptor.truncate(100) } } } ``` 注意:`truncate`方法在`FileDescriptor`上可用,但需要以读写方式打开文件。 ### 5. 替代固定(Pinning)的其他方法 如果固定文件的目的是为了确保文件不被删除,那么可以考虑以下方法: - 将文件保存到应用的私有目录(不需要权限,且不会被其他应用访问)。 - 使用MediaStore API保存到公共目录,并设置文件为不可删除(但用户仍然可以删除)。 - 对于重要文件,可以备份到云端。 ### 6. 适配旧版本 如果应用需要支持旧版本Android,可以使用条件判断: ```kotlin if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { // 使用分区存储的方法 } else { // 使用旧方法,如File API } ``` 综上所述,自Android Q起,文件固定(Pinning)被弃用,我们应使用分区存储推荐的方法,包括MediaStore API和存储访问框架(SAF),对于需要固定文件大小的场景,可以使用`FileDescriptor.truncate()`方法。 引用说明: [^1]:对于Android Q以下,根据我们上面的设备信息分析,可以根据IMEI+AndroidID+Serial Number来确定唯一设备ID。 [^2]:Android Q 适配。从AndroidQ开始,应用必须具有READ_PRIVILEGED_PHONE_STATE签名权限才能访问设备的不可重置标识符(包含IMEI和序列号)。 [^4]:本文讲述在安卓高版本例如安卓Q中 快速调用系统相机或相册进行图片操作的过程。 相关问题: 1. 在Android Q中如何请求存储访问框架(SAF)的权限? 2. 如何在Android Q中访问和管理媒体文件? 3. 在Android Q中,如何将文件保存到应用的私有目录? 4. 如何适配Android Q的分区存储? 5. 在Android Q中,如何检查文件是否存在? 6. 如何通过MediaStore API获取图片的缩略图? </think>## Android Q 起文件固定(Pinning)被弃用的适配方案 自 Android Q (API 29) 起,文件固定(Pinning)功能被弃用,开发者需要使用新的存储管理方法。以下是完整的解决方案: ### 1. **理解变更原因** - **Pinning 被弃用**:在 Android Q 之前,开发者使用 `StorageManager.pinFile()` 固定文件防止被删除 - **Android Q 引入分区存储**:应用只能访问自己的沙盒目录和特定类型的共享文件 - **替代方案**:使用 `trim()` 方法管理存储空间[^4] ### 2. **使用 `trim()` 方法替代 Pinning** ```kotlin val storageManager = getSystemService(STORAGE_SERVICE) as StorageManager // 创建修剪请求 val trimRequest = StorageManager.allocateBytes(fileDescriptor, 0L) // 执行修剪 storageManager.trim(StorageManager.UUID_DEFAULT, trimRequest) { bytes -> if (bytes >= 0) { Log.d("Storage", "释放空间: $bytes 字节") } else { Log.e("Storage", "修剪失败") } } ``` ### 3. **文件操作适配方案** #### a. 访问应用专属目录 ```kotlin // 获取应用专属文件目录 val internalFilesDir = context.filesDir val externalFilesDir = context.getExternalFilesDir(null) // 创建新文件 val newFile = File(externalFilesDir, "example.txt") newFile.writeText("Hello Android Q") ``` #### b. 访问媒体文件 使用 MediaStore API: ```kotlin val projection = arrayOf( MediaStore.Images.Media._ID, MediaStore.Images.Media.DISPLAY_NAME ) val selection = "${MediaStore.Images.Media.DATE_ADDED} >= ?" val selectionArgs = arrayOf( (System.currentTimeMillis() - DateUtils.DAY_IN_MILLIS).toString() ) val cursor = contentResolver.query( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, selection, selectionArgs, "${MediaStore.Images.Media.DATE_ADDED} DESC" ) ``` ### 4. **处理大文件存储** 对于特殊类型的文件(如视频、大型文档): ```kotlin // 请求存储权限 val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply { addCategory(Intent.CATEGORY_OPENABLE) type = "video/mp4" putExtra(Intent.EXTRA_TITLE, "my_video.mp4") } startActivityForResult(intent, CREATE_FILE_REQUEST) // 在 onActivityResult 中处理 override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { if (requestCode == CREATE_FILE_REQUEST && resultCode == RESULT_OK) { data?.data?.let { uri -> contentResolver.openOutputStream(uri)?.use { stream -> // 写入文件内容 stream.write(videoData) } } } } ``` ### 5. **适配旧版本 Android** ```kotlin fun manageStorage(file: File, context: Context) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { // Android 10+ 使用 trim() val parcelFileDescriptor = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_WRITE) val storageManager = context.getSystemService(STORAGE_SERVICE) as StorageManager storageManager.trim(StorageManager.UUID_DEFAULT, 0) } else { // 旧版本使用 pinFile (已弃用但可兼容) val storageManager = context.getSystemService(STORAGE_SERVICE) as StorageManager storageManager.pinFile(file) } } ``` ### 6. **最佳实践建议** 1. **使用 SAF (存储访问框架)**:通过 Intent 让用户选择文件位置 2. **优先访问应用专属目录**:不需要权限即可读写 3. **及时释放空间**:定期调用 `trim()` 清理不再需要的文件 4. **使用 ContentResolver**:替代直接文件路径访问[^4] 5. **适配分区存储**:在 AndroidManifest 中声明: ```xml <application android:requestLegacyExternalStorage="true" ... > ``` > **注意**:`requestLegacyExternalStorage` 是临时方案,应尽快适配分区存储 ### 7. **错误处理** ```kotlin try { storageManager.trim(StorageManager.UUID_DEFAULT, trimRequest) } catch (e: IOException) { when { Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && e is RecoverableSecurityException -> { // 请求文件访问权限 requestFileAccessPermission(e.userAction) } else -> { // 其他错误处理 showError("存储操作失败: ${e.message}") } } } ``` 通过以上方案,您可以有效替代已弃用的 Pinning 功能,并适配 Android Q 及更高版本的存储管理要求。建议优先使用存储访问框架(SAF)和 MediaStore API 进行文件操作[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值