前言
我在一個項目中需要給用戶自定義保存數據的路徑,但是現有的原生方法都是選取文件的,不能只選取文件夾,只好瞭解一下,做個文件夾路徑選取的自定義頁面。當然,獲取文件路徑也一樣。
圖
流程
註冊權限
我們需要在AndroidManifest.xml註冊兩個權限,分別是外置存儲的讀和寫的權限。
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
請求權限
這個簡單,大家應該都很熟悉,我使用了base類
// 檢查權限
fun checkPermission(permission: String) : Boolean {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return true
return checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED
}
// 請求權限
fun reqPermission(permissions: Array<String>, reqCode: Int) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return
requestPermissions(permissions, reqCode)
}
判斷權限與請求
if (!checkPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) ||
!checkPermission(Manifest.permission.READ_EXTERNAL_STORAGE)) {
reqPermission(arrayOf(
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE),
P_WR_EXTERNAL_STORAGE
)
return
}
請求權限回調
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
val pass = !grantResults.contains(PackageManager.PERMISSION_DENIED)
when(requestCode) {
P_WR_EXTERNAL_STORAGE -> {
// 獲取讀寫權限
if (pass) {
// 更新當前路徑文件夾列表
updateArray()
}
}
}
}
文件夾信息實體類
FolderInfo.kt
/**
* 文件夾信息
*
* @author D10NG
* @date on 2019-12-06 10:04
*/
data class FolderInfo(
/** 圖標 */
var iconRes: Int = R.mipmap.icon_folder,
/** 名稱 */
var name: String = "",
/** 子文件個數 */
var sonNum: Long = 0L,
/** 最後修改時間 */
var lastEditTime: String = "",
/** 路徑 */
var path: String = ""
) : Serializable {
}
代碼邏輯
一個常量,一個變量
一個常量:最原始最基本的默認路徑
private lateinit var baseDirectory: String
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
...
baseDirectory = applicationContext.externalCacheDir?.path?: applicationContext.filesDir.path
}
一個變量:當前的文件夾路徑
private lateinit var curPath: String
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
...
// 獲取傳遞過來的路徑
curPath = intent.getStringExtra("path")?: baseDirectory
}
刷新文件夾列表
你可以在判斷文件夾類型裏增加自己想要的文件類型,添加到列表裏,顯示出來。
/**
* 更新文件夾列表
*/
private fun updateArray() {
folderAdapter.update(getFolderArray(curPath))
}
/**
* 根據路徑獲取全部文件夾
*/
private fun getFolderArray(path: String): MutableList<FolderInfo> {
val files = File(path).listFiles()?: emptyArray()
val fList = mutableListOf<FolderInfo>()
val fileList = files.asList()
// 文件排序--按照名稱排序
Collections.sort(fileList, object : Comparator<File>{
override fun compare(p0: File?, p1: File?): Int {
if (p0 == null) return -1
if (p1 == null) return 1
return p0.name.compareTo(p1.name)
}
})
for (file in fileList.iterator()) {
if (file == null) continue
// 在這裏判斷文件類型
if (file.isDirectory && !file.isHidden) {
val info = FolderInfo()
info.iconRes = R.mipmap.icon_folder
info.name = file.name
info.path = file.path
info.sonNum = getSonFolderNumber(file.path)
info.lastEditTime = DateUtils.getDateStr(file.lastModified(), "yyyy-MM-dd hh:mm:ss")
fList.add(info)
}
}
return fList
}
/**
* 獲取文件夾的子文件夾數量
*/
private fun getSonFolderNumber(path: String) : Long {
var number = 0L
val files = File(path).listFiles()?: emptyArray()
for (file in files.iterator()) {
if (file == null) continue
if (file.isDirectory && !file.isHidden) {
number ++
}
}
return number
}
跳到上一個文件夾
fun lastPage(view: View) {
// 返回上一頁,如果到了盡頭提示用戶
val file = File(binding.curPath?: baseDirectory)
val parentPath = file.parent
if (parentPath == null) {
showSnackBar(binding.root, "已經是根目錄了")
} else {
binding.curPath = parentPath
updateArray()
}
}
完事
主要的邏輯都在上面了,剩下的都是些頁面佈局之類的定製化的東西就不發出來了。相信各位都可以舉一反三。