Android学习笔记-Android10文件访问适配
需求:需要能浏览应用外存储空间的文件
问题点:传统方案不能兼容Android10以上的系统
解决思路:利用系统文件浏览器找到指定的文件,在
onActivityResult
回调中拿到Uri,在从Uri中拿到流,将文件转存到应用内存储
/*如果是Android10以上设备,则调用系统文件浏览器*/ if (Build.VERSION.SDK_INT >= 29){ val intent = Intent(Intent.ACTION_OPEN_DOCUMENT) .apply { // Provide read access to files and sub-directories in the user-selected // directory. addCategory(Intent.CATEGORY_OPENABLE) type = "*/*" } startActivityForResult(intent, Constants.CODE.REQUEST_SERIES) }
在回调中处理(主要代码):
1 override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (resultCode == Activity.RESULT_OK && requestCode == Constants.CODE.REQUEST_SERIES){ data?.data?.let { Log.e(TAG,it.toString()) dumpImageMetaData(it) } } else if (requestCode == Constants.CODE.REQUEST_SERIES){ dismiss() } } /** * 处理选中的文件,只支持单文件。如果是多选则只处理第一个 * 该方法涉及IO操作 */ private fun dumpImageMetaData(uri: Uri) { // The query, because it only applies to a single document, returns only // one row. There's no need to filter, sort, or select fields, // because we want all fields for one document. val cursor: Cursor? = context?.contentResolver?.query( uri, null, null, null, null, null) cursor?.use { // moveToFirst() returns false if the cursor has 0 rows. Very handy for // "if there's anything to look at, look at it" conditionals. if (it.moveToFirst()) { // Note it's called "Display Name". This is // provider-specific, and might not necessarily be the file name. val displayName: String = it.getString(it.getColumnIndex(OpenableColumns.DISPLAY_NAME)) Log.i(TAG, "Display Name: $displayName") var file = File(FileUtils.SDPATH + displayName) if (file.exists()){ Log.i(TAG,"File exists") } var inputStream = context?.contentResolver?.openInputStream(uri) var outPutStream = FileOutputStream(file) var bufferIn = BufferedInputStream(inputStream) var bufferOut = BufferedOutputStream(outPutStream) val b = ByteArray(1024) while (bufferIn.read(b) != -1){ bufferOut.write(b) } bufferIn.close() bufferOut.close() val sizeIndex: Int = it.getColumnIndex(OpenableColumns.SIZE) // If the size is unknown, the value stored is null. But because an // int can't be null, the behavior is implementation-specific, // and unpredictable. So as // a rule, check if it's null before assigning to an int. This will // happen often: The storage API allows for remote files, whose // size might not be locally known. val size: String = if (!it.isNull(sizeIndex)) { // Technically the column stores an int, but cursor.getString() // will do the conversion automatically. it.getString(sizeIndex) } else { "Unknown" } } } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架