Android 自定义选取文件路径页面主要逻辑解析

Android 自定义选取文件路径页面主要逻辑解析

  • 前言
  • 流程
    • 注册权限
    • 请求权限
    • 文件夹信息实体类
    • 代码逻辑
      • 一个常量,一个变量
      • 刷新文件夹列表
      • 跳到上一个文件夹
  • 完事

前言

我在一个项目中需要给用户自定义保存数据的路径,但是现有的原生方法都是选取文件的,不能只选取文件夹,只好了解一下,做个文件夹路径选取的自定义页面。当然,获取文件路径也一样。

Android 自定义选取文件路径页面主要逻辑解析_第1张图片

流程

注册权限

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

完事

主要的逻辑都在上面了,剩下的都是些页面布局之类的定制化的东西就不发出来了。相信各位都可以举一反三。

你可能感兴趣的:(Android知识面)