文件管理器ZFileManager阅读---01

121 阅读3分钟

github.com/ttylinux/ZF…

入口,MainActivity, 选择Activity+Fragment的格式;

展示的样式是,在一个Activity里面包含一个Fragment,不断点击,不断变换当前Fragment的的外观。

R.id.main_rb_af -> {

    FragmentSampleActivity2.jump(this, 1)

}

初始化,启动,

private fun init1() {

    vb.fs2.visibility = View.VISIBLE

    vb.fs2Vp.visibility = View.GONE

    val TAG = "ZFileListFragmentTag"

    getZFileConfig().fragmentTag = TAG

    /*supportFragmentManager

        .beginTransaction()

        .add(R.id.fs2, getZFragment(), TAG)

        .commit()*/

  **  zfileInitAndStart(R.id.fs2, mListener)**

}
private var mListener: ZFragmentListener? = object : ZFragmentListener() {

.....}

mListener函数,监听有哪些文件被选中,获取具体的文件信息。用来获取选中的文件信息的。

private var mListener: ZFragmentListener? = object : ZFragmentListener() {

    /**

     * 文件选择

     */

    override fun selectResult(selectList: MutableList<ZFileBean>?) {

        Toast.makeText(this@FragmentSampleActivity2, "选中了${selectList?.size}个,具体信息查看log", Toast.LENGTH_SHORT).show()

        Log.i("ZFileManager", "选中的值 ===>>> ")

        selectList?.forEach {

            Log.i("ZFileManager", it.toString())

        }

        finish()

    }

  

    /**

     * 获取 [Manifest.permission.WRITE_EXTERNAL_STORAGE] 权限失败

     * @param activity FragmentActivity

     */

    override fun onSDPermissionsFiled(activity: FragmentActivity) {

        Toast.makeText(this@FragmentSampleActivity2, "OPS,没有SD卡权限", Toast.LENGTH_SHORT).show()

    }
    /**

     * 获取 [Environment.isExternalStorageManager] (所有的文件管理) 权限 失败

     * 请注意:Android 11 及以上版本 才有

     */

    override fun onExternalStorageManagerFiled(activity: FragmentActivity) {

        Toast.makeText(this@FragmentSampleActivity2, "Environment.isExternalStorageManager = false", Toast.LENGTH_SHORT).show()

    }

}

调用库函数:

/**

* 在 [FragmentActivity] 中 [FragmentActivity.onCreate] 使用 --->>> 仅支持 [ZFileListFragment] 嵌套 [FragmentActivity] 中使用

*/

fun FragmentActivity.zfileInitAndStart(id: Int, zFragmentListener: ZFragmentListener?) {

    val fragment = ZFileListFragment.newInstance()

    fragment.zFragmentListener = zFragmentListener

    supportFragmentManager.beginTransaction()

        .add(id, fragment, getZFileConfig().fragmentTag)

        .commit()

}

文件库函数的实现:

关键类: ZFileListFragment

return ZFileListFragment().apply {

    arguments = Bundle().run {

        putString(FILE_START_PATH_KEY, newPath)

        this

    }

}

ZFileListFragment,只需要一个路径参数作为初始化

  


  


/**

* 文件管理 核心实现,可以 在 Activity、Fragment or ViewPager中使用

*

* 注意:使用 [FragmentManager] 或者 [ViewPager] 动态添加或直接嵌套使用时

* 1. 无法通过 [ZFileDsl] 获取返回的数据,其他配置将不受影响

* 2. 需在 Activity 中配置 [ZFragmentListener] 来接收选中的文件

* 3. Activity onBackPressed 方法 需要 调用 [onBackPressed]

* 4. Activity onResume 方法 需要调用 [showPermissionDialog]

*/

class ZFileListFragment : Fragment() {

  


........

  }

  


  


ZFileListFragment:

  


override fun onCreateView(

    inflater: LayoutInflater,

    container: ViewGroup?,

    savedInstanceState: Bundle?

): View? {

    vb = FragmentZfileListBinding.inflate(inflater, container, false)

    return vb?.root

}

1.初始化界面


override fun onViewCreated(view: View, savedInstanceState: Bundle?) {

    super.onViewCreated(view, savedInstanceState)

    if (!getZFileConfig().needLazy) {

        initAll()

    }

}

2.如果不是懒加载,则在View创建完毕的时候,初始化initAll()

initAll函数做的工作,设置初始化的文件路径,检测是否有读取文件的权限,初始化UI

  


如果是有读取文件的权限,则进行文件路径信息的获取

  

3.文件路径信息的获取,初始化

private var rootPath = "" // 根目录

private var specifyPath: String? = "" // 指定目录

private var nowPath: String? = "" // 当前目录

    set(value) {

        field = value

        getZFileHelp().setCurrentPath(value)

    }

  


  


private fun initRV() {

    hasPermission = true

    setPermissionState(View.GONE)



    vb?.zfileListRefreshLayout?.property {

        getData(nowPath)

    }

    initPathRecyclerView()

    initListRecyclerView()

}

初始化,initAll的时候,当前路径是设置为根路径

nowPath = rootPath;

  


  


4.获取当前路径下的所有文件信息

getData(nowPath)

ZFileUtil.getList(requireContext()) {

    if (isNullOrEmpty()) {

..............................

    } else {

        vb?.zfileListRefreshLayout?.isRefreshing = false

      **fileListAdapter?.setDatas(this)**

        vb?.zfileListListRecyclerView?.scrollToPosition(0)

        setEmptyState(View.GONE)

        setDoState(View.GONE)

    }

}


返回的文件信息,用MutableList<ZFileBean>表示

internal object ZFileUtil {

    /**

     * 获取文件

     */

    fun getList(context: Context, block: MutableList<ZFileBean>?.() -> Unit) {

        ZFileListAsync(context, block).start(getZFileConfig().filePath)

    }

----

}

 
internal class ZFileListAsync(

    context: Context,

    block: MutableList<ZFileBean>?.() -> Unit

) : ZFileAsync(context, block) {

    override fun doingWork(filePath: String?) =

        getZFileHelp().getFileLoadListener().getFileList(getContext(), filePath)

}

/**

* 更方便的去获取符合要求的数据

*/

open class ZFileAsync(

    private var context: Context,

    private var block: MutableList<ZFileBean>?.() -> Unit

) {

  


/**

* 获取数据

* @param filterArray 过滤规则

*/

fun start(filterArray: Array<String>) {

    doStart()

    async {

        sendMessage(OTHER, doingWork(filterArray))  //这段代码在第三方线程中执行----(1)

    }

}

  


//private var block: MutableList<ZFileBean>?.() -> Unit

  


private fun onPostExecute(list: MutableList<ZFileBean>?) {

    destory()

    block.invoke(list)  //handler获取到文件信息之后,执行block代码,这时候,执行的是UI线程---(2)

  


    onPostExecute()

}

  


/**

* 获取数据

* @param filterArray  过滤规则

*/

protected open fun doingWork(filterArray: Array<String>): MutableList<ZFileBean>? {

    return null

}

 .......

  }

  


internal fun async(block: () -> Unit) {

    getZFileHelp().getPoolExecutor().execute(object : Thread() {

        override fun run() {

            block()

        }

    })

}

 

5.获取当前路径下的所有文件信息,具体实现:

   override fun doingWork(filePath: String?) =

        getZFileHelp().getFileLoadListener().getFileList(getContext(), filePath)

/**

* 文件数据获取

*/

private var fileLoadListener: ZFileLoadListener = ZFileDefaultLoadListener()

internal fun getFileLoadListener() = fileLoadListener

/**

* 完全自定义 获取文件数据 (可通过 [File.toZFileBean] 自动转换数据)

*/

interface ZFileLoadListener {


    /**

     * 获取手机里的文件List

     * @param filePath String           指定的文件目录访问,空为SD卡根目录

     * @return MutableList<ZFileBean>?  list

     */

    fun getFileList(context: Context?, filePath: String?): MutableList<ZFileBean>?

}

 

internal class ZFileDefaultLoadListener : ZFileLoadListener {

    /**

     * 获取手机里的文件List

     * @param filePath String?          指定的文件目录访问,空为SD卡根目录

     * @return MutableList<ZFileBean>?  list

     */

    override fun getFileList(context: Context?, filePath: String?) =

        getDefaultFileList(context, filePath)

  


  


    private fun getDefaultFileList(context: Context?, filePath: String?): MutableList<ZFileBean> {

        val path = if (filePath.isNullOrEmpty()) SD_ROOT else filePath

        val config = getZFileConfig()

        val list = arrayListOf<ZFileBean>()

        val listFiles = path.toFile().listFiles(

            ZFileFilter(

                config.fileFilterArray,

                config.isOnlyFolder,

                config.isOnlyFile

            )

        )

        if (listFiles.isNullOrEmpty()) return list

        for (it in listFiles) {

            if (it.path == SAF_DATA_PATH || it.path == SAF_OBB_PATH) {

                if (config.showDataAndObbFolder) {

                    addFileToList(config, list, it)

                } else {

                    continue

                }

            } else {

                addFileToList(config, list, it)

            }

        }

        ZFileSth.sortord(list)

        return list

    }

  


  


    private fun addFileToList(

        config: ZFileConfiguration,

        list: MutableList<ZFileBean>,

        file: File

    ) {

        if (config.showHiddenFile) {

            list.add(file.toZFileBean())

        } else {

            if (!file.isHidden) {

                list.add(file.toZFileBean())

            }

        }

    }
}