Android 自定義選取文件路徑頁面主要邏輯解析

前言

我在一個項目中需要給用戶自定義保存數據的路徑,但是現有的原生方法都是選取文件的,不能只選取文件夾,只好瞭解一下,做個文件夾路徑選取的自定義頁面。當然,獲取文件路徑也一樣。

在這裏插入圖片描述

流程

註冊權限

我們需要在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()
        }
    }

完事

主要的邏輯都在上面了,剩下的都是些頁面佈局之類的定製化的東西就不發出來了。相信各位都可以舉一反三。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章