Android kotlin語(yǔ)言實(shí)現(xiàn)刪除文件的解決方案
一、前言
在項(xiàng)目開(kāi)發(fā)過(guò)程中,尤其是需要跨平臺(tái)協(xié)作的項(xiàng)目,那么刪除用戶指定的文件的這種操作就顯得尤為重要了。但是在Android11+的操作系統(tǒng)中,權(quán)限聲明變得復(fù)雜了起來(lái),而且大多數(shù)的解決方案多為Java語(yǔ)言,kotlin語(yǔ)言的解決方案甚少,而且大多數(shù)的解決方案也沒(méi)有用。
本人也是尋求多日無(wú)果后嘗試多種解決方案拼合最終發(fā)現(xiàn)的本解決方案,在這里給廣大開(kāi)發(fā)者同志們提供一個(gè)模板,各位同志可以在本模版的基礎(chǔ)上進(jìn)行改寫(xiě),從而減少無(wú)謂查詢(xún)資料工作。
二、適用環(huán)境
語(yǔ)言:kotlin
操作系統(tǒng)版本:Android7+(本方案已經(jīng)對(duì)Android11+和Android7-10進(jìn)行了區(qū)分,可以放心使用)
三、模板內(nèi)容
1.權(quán)限申請(qǐng)
首先在AndroidManifest.xml中必須注冊(cè)這三項(xiàng)權(quán)限:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission
android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />完整的AndroidManifest.xml示例如下所示:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.AbstractFunctionDemo"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission
android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />
</manifest>2.Activity中的模板
本人在模板中按步驟寫(xiě)了注釋了,廣大開(kāi)發(fā)者同志在復(fù)制走后,按照注釋的流程消化,然后進(jìn)行簡(jiǎn)單的改寫(xiě)即可。
完整模板(MainActivity.kt)如下:
package com.example.abstractfunctiondemo
import android.os.Bundle
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import android.Manifest
import android.app.Activity
import android.content.ContentUris
import android.content.ContentValues
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.provider.Settings
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.DocumentsContract
import android.provider.MediaStore
import android.provider.OpenableColumns
import android.util.Log
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.documentfile.provider.DocumentFile
import com.google.android.material.button.MaterialButton
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.OutputStream
class MainActivity : AppCompatActivity() {
/**
* 1.定義選擇器的公共變量
*
* 定義這個(gè)全局變量是因?yàn)楸仨氃趏nCreate的時(shí)候就注冊(cè),
* 不可以現(xiàn)用現(xiàn)注冊(cè)
*/
private lateinit var filePickerLauncher: androidx.activity.result.ActivityResultLauncher<Intent>
private var onFilePicked: ((String) -> Unit)? = null
/**
* 定義目標(biāo)文件路徑的公共變量
*/
private var sourceFilePath: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_main)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
/**
* 5.注冊(cè)文件選擇器
*/
filePickerLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
val uri: Uri? = result.data?.data
if (uri != null) {
Log.e("選取文件", "選擇的文件 URI: $uri")
onFilePicked?.invoke(uri.toString()) // ? 直接返回 `Uri`
deleteFileByUri(uri) // ? 直接用 `Uri` 刪除
Log.e("選取文件", "執(zhí)行結(jié)束")
} else {
Toast.makeText(this, "無(wú)法獲取文件", Toast.LENGTH_SHORT).show()
}
} else {
Toast.makeText(this, "未選擇文件", Toast.LENGTH_SHORT).show()
}
}
val testButton2: MaterialButton = findViewById(R.id.testButton2)
testButton2.setOnClickListener {
/**
* 6.調(diào)用
*/
if (checkAndRequestPermissions()) {
pickFile()
}
}
}
/**
* 2.定義文件選擇器激活函數(shù)
*/
private fun pickFile() {
filePickerLauncher.launch(Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
type = "*/*"
})
}
/**
* 3.定義URI解析函數(shù)
*/
private fun getFilePathFromUri(uri: Uri): String? {
val context = applicationContext
var filePath: String? = null
if (uri.scheme == "content") {
val projection = arrayOf(MediaStore.Files.FileColumns.DATA)
context.contentResolver.query(uri, projection, null, null, null)?.use { cursor ->
if (cursor.moveToFirst()) {
val columnIndex =
cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.DATA)
filePath = cursor.getString(columnIndex)
}
}
}
return filePath
}
/**
* 4.定義文件刪除函數(shù)
*/
private fun deleteFileByUri(uri: Uri) {
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
// ? Android 10+ 需要用 `DocumentsContract.deleteDocument()`
val deleted = DocumentsContract.deleteDocument(contentResolver, uri)
if (deleted) {
Log.e("刪除文件", "文件刪除成功: $uri")
Toast.makeText(this, "文件刪除成功", Toast.LENGTH_SHORT).show()
} else {
Log.e("刪除文件", "文件刪除失敗: $uri")
Toast.makeText(this, "無(wú)法刪除文件", Toast.LENGTH_SHORT).show()
}
} else {
// ? Android 9 及以下,嘗試轉(zhuǎn)換為文件路徑
val filePath = getFilePathFromUri(uri)
if (filePath != null) {
val file = File(filePath)
if (file.exists() && file.delete()) {
Log.e("刪除文件", "文件刪除成功: $filePath")
Toast.makeText(this, "文件刪除成功", Toast.LENGTH_SHORT).show()
} else {
Log.e("刪除文件", "文件刪除失敗: $filePath")
Toast.makeText(this, "無(wú)法刪除文件", Toast.LENGTH_SHORT).show()
}
} else {
Toast.makeText(this, "無(wú)法獲取文件路徑,嘗試手動(dòng)刪除", Toast.LENGTH_SHORT).show()
}
}
} catch (e: Exception) {
e.printStackTrace()
Toast.makeText(this, "刪除文件出錯(cuò): ${e.message}", Toast.LENGTH_SHORT).show()
}
}
}以上就是Android kotlin語(yǔ)言實(shí)現(xiàn)刪除文件的解決方案的詳細(xì)內(nèi)容,更多關(guān)于Android kotlin刪除文件的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Kotlin協(xié)程launch啟動(dòng)流程原理詳解
這篇文章主要為大家介紹了Kotlin協(xié)程launch啟動(dòng)流程原理詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12
Android編程實(shí)現(xiàn)屏幕禁止休眠的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)屏幕禁止休眠的方法,分析了Android的Manifest.xml設(shè)置與代碼實(shí)現(xiàn)兩種操作技巧,需要的朋友可以參考下2016-10-10
android?studio實(shí)現(xiàn)簡(jiǎn)易的計(jì)算器
這篇文章主要為大家詳細(xì)介紹了android?studio實(shí)現(xiàn)簡(jiǎn)易的計(jì)算器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05
Android開(kāi)發(fā)RecyclerView性能優(yōu)化之異步預(yù)加載
這篇文章主要介紹了Android開(kāi)發(fā)RecyclerView性能優(yōu)化之異步預(yù)加載實(shí)現(xiàn)解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06
Android中多行文本末尾添加圖片排版問(wèn)題的解決方法
這篇文章主要給大家介紹了關(guān)于Android中多行文本末尾添加圖片排版問(wèn)題的解決方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2018-07-07
自定義RadioButton和ViewPager實(shí)現(xiàn)TabHost帶滑動(dòng)的頁(yè)卡效果
在工作中又很多需求都不是android系統(tǒng)自帶的控件可以達(dá)到效果的所以這個(gè)時(shí)候就要自定義控件來(lái)達(dá)到效果:使用自定義RadioButton和ViewPager實(shí)現(xiàn)TabHost帶滑動(dòng)的頁(yè)卡效果2013-01-01
深入Android中BroadcastReceiver的兩種注冊(cè)方式(靜態(tài)和動(dòng)態(tài))詳解
這篇文章主要介紹了深入Android中BroadcastReceiver的兩種注冊(cè)方式(靜態(tài)和動(dòng)態(tài))詳解,具有一定的參考價(jià)值,有需要的可以了解一下。2016-12-12
Android studio 2020中的Android SDK 下載教程
這篇文章主要介紹了Android studio 2020中的Android SDK 下載教程,本文圖文并茂給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-03-03

