一、前言

我在使用我们的App的时候发现发送文件的时候,从进入文件选择界面到文件完全加载出来,时间过长,大概10s左右,然后我想这个是否可以优化一下,然后进过自己查资料,瞎搞,弄出啦了。下面不多说,先上效果图(实现的UI可以各位自行实现,我这里只是提供文件扫描功能的实现)。
- 说明:
我们这个文件扫描是基于 https://github.com/DroidNinja/Android-FilePicker 这个开源框架的(这个框架还不错,可以对文件进行归类),这里只是进行了优化。


  • 效果图如下:
  • 优化思路:
    1、基于原有的方案,优化代码;
    2、在不改变原有框架的前提下,寻找替代原有扫描文件方法的方案;
    3、剔除原有的扫描文件方案,找一个更优的框架进行替换。

二、思路实现说明

  • 2.1 剔除原有的扫描文件方案,找一个更优的框架进行替换
    该方案被第一个排除:
    i、因为之前框架涉及的代码比较多,改动可能比较大,担心影响功能
    ii、看了一些框架,对比于原有的,不符合原有设计需求

  • 2.2 在不改变原有框架的前提下,寻找替代原有扫描文件方法的方案
    我在网上看了一个大牛的扫描方案 https://blog.csdn.net/bingjianit/article/details/78822490,大家可以看一看。他的大体思路如下:
    i、扫描全盘文件,剔除隐藏文件或者文件夹。
    ii、将文件夹存入专门存放文件夹的队列中,并且为每个文件夹创建一个线程,将当前的文件夹中的指定文件存入集合中
    iii、开启线程池,执行所有线程,执行效果类似于第二步,直到所有文件夹都遍历完(直到所有线程执行完毕),将所有文件输出。
    我将该方案替代我之前的扫描方案的代码中,运行发现扫描的速度与之前方案对比,扫描速度似乎更慢。我猜测问题可能是线程过多。经过查看原方案的代码,并与这个方案进行对比,排除了这个方案。

  • 2.3 基于原有的方案,优化代码
    排除了上面两个方案,那只能改进现有代码了(回到原地),通过查看原有方案的扫描文件的源码,发现该方案的实现方式是通过contentprovider进行查询(由此确定可能该实现方法可能是最快的),经过查询资料发现contentprovider存储文件的方式类似于数据库(好久没用这个contentprovider,忘了,哈哈),我后来发现这个查询文件是不是可以通过mime_type这个字段进行查询,然后下面就开始进入正文:
    首先先给一个各种文件对应的mime_type的链接 https://blog.csdn.net/mazaiting/article/details/78129532,这里面包好了.doc .mp4等等文件对应的mime_type。
    下面看扫描文件的核心方法:

context.getContentResolver().query(uri,projection,selection,selectionArgs,MediaStore.Files.FileColumns.DATE_ADDED + " DESC");

说明:该方法类似于数据库查询的方法。它有5个参数,这些参数我这里只做简单的描述,具体的大家可以自己自行百度。

参数 描述 举例
uri 内容提供者中文件的路径 比如:音频(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI)
projection 需要查询出来的列 文件的_id 文件的大小等
selection 查询的条件 指定一个查询的条件,比如 selection = “mime_type = ?”;
selectionArgs 查询的条件的值 比如:selectionArgs = new String[]{“video/mp4”};
sortOrder 排序 比如:MediaStore.Files.FileColumns.DATE_ADDED + ” DESC”

下面贴实现代码(导包移除):

/*** TODO 扫描文件*/
public class DocScannerTask extends AsyncTask<Void, Void, List<Document>> {List<Runnable> runnables = new ArrayList<>();final String[] DOC_PROJECTION = {MediaStore.Images.Media._ID,MediaStore.Images.Media.DATA,MediaStore.Files.FileColumns.MIME_TYPE,MediaStore.Files.FileColumns.SIZE,MediaStore.Files.FileColumns.TITLE};final String[] projection = DOC_PROJECTION;private final FileResultCallback<Document> resultCallback;ArrayList<Document> allFiles = new ArrayList<>();//TODO 指定扫描的文件类型String[] selectionArgs = new String[]{".doc", ".docx", ".xls", ".xlsx", ".pdf", ".txt", ".rar", ".html", ".mp3", ".mp4", ".apk"};private final Context context;List<Cursor> list = new ArrayList<>();public DocScannerTask(Context context, FileResultCallback<Document> fileResultCallback) {this.context = context;this.resultCallback = fileResultCallback;}/*** TODO 子线程请求数据** @param voids* @return*/@Overrideprotected List<Document> doInBackground(Void... voids) {final ArrayList<Document> documents = new ArrayList<>();for (int i = 0; i < 4; i++) {final int j = i;Runnable runnable = new Runnable() {@Overridepublic void run() {documents.addAll(getAllFiles(j));}};runnables.add(runnable);}final ExecutorService executorService = Executors.newFixedThreadPool(3);for (Runnable runnable : runnables) {executorService.execute(runnable);}executorService.shutdown();//等待线程池中的所有线程运行完成while (true) {if (executorService.isTerminated()) {break;}}return documents;}private ArrayList<Document> getAllFiles(int i) {String selection = null;String[] selectionArgs = null;Uri uri = MediaStore.Files.getContentUri("external");if (i == 0) {  //一些能通过mime_type查询出来的文档 .doc .pdf .txt .apkselection = "mime_type = ? or mime_type = ? or mime_type = ? or mime_type = ? ";selectionArgs = new String[]{"text/html", "application/msword", "application/pdf", "text/plain"};} else if (i == 1) { //一些不能通过mime_type查询出来的文档 .docx .xls .xlsx .rarselection = "(" + MediaStore.Files.FileColumns.DATA + " LIKE '%.xls'" +" or " + MediaStore.Files.FileColumns.DATA + " LIKE '%.docx'" +" or " + MediaStore.Files.FileColumns.DATA + " LIKE '%.apk'" +" or " + MediaStore.Files.FileColumns.DATA + " LIKE '%.xlsx'" +" or " + MediaStore.Files.FileColumns.DATA + " LIKE '%.rar'" + ")";selectionArgs = null;} else if (i == 2) { //视频文件uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;selection = "mime_type = ?";selectionArgs = new String[]{"video/mp4"};} else if (i == 3) {  //音频文件uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;selection = "mime_type = ? or mime_type = ?";selectionArgs = new String[]{"audio/mpeg", "audio/ogg"};
}
ArrayList<Document> documents = new ArrayList<>();final Cursor cursor = context.getContentResolver().query(uri,projection,selection,selectionArgs,MediaStore.Files.FileColumns.DATE_ADDED + " DESC");if (cursor != null) {documents = getDocumentFromCursor(cursor);cursor.close();}return documents;}@Overrideprotected void onPostExecute(List<Document> documents) {super.onPostExecute(documents);if (resultCallback != null) {resultCallback.onResultCallback(documents);}}/*** TODO 从Cursor中获取数据** @param data* @return*/private ArrayList<Document> getDocumentFromCursor(Cursor data) {ArrayList<Document> documents = new ArrayList<>();while (data.moveToNext()) {int imageId = data.getInt(data.getColumnIndexOrThrow(_ID));String path = data.getString(data.getColumnIndexOrThrow(DATA));String title = data.getString(data.getColumnIndexOrThrow(MediaStore.Files.FileColumns.TITLE));//TODO 判断文件路径是否是指定的文件类型if (path != null && contains(selectionArgs, path)) {Document document = new Document(imageId, title, path);String mimeType = data.getString(data.getColumnIndexOrThrow(MediaStore.Files.FileColumns.MIME_TYPE));if (mimeType != null && !TextUtils.isEmpty(mimeType))document.setMimeType(mimeType);else {document.setMimeType("");}document.setSize(data.getString(data.getColumnIndexOrThrow(MediaStore.Files.FileColumns.SIZE)));if (!documents.contains(document))documents.add(document);}}return documents;}/*** TODO 判断文件路径是否是types结尾** @param types 扫描的文件类型* @param path  文件路径* @return*/boolean contains(String[] types, String path) {for (String string : types) {if (path.endsWith(string)) {return true;}}return false;}
}

代码实现说明:我一开始实现是完全用一个selection 和 selectionArgs 进行查询,发现速度很快,只需要大概1s就能完全加载完(从进入到显示)。查询的两个字段如下:

selection = "mime_type = ? or mime_type = ? or mime_type = ? or mime_type = ? or mime_type = ? or mime_type = ? or mime_type = ? or mime_type = ? or mime_type = ? or mime_type = ? or mime_type = ? or mime_type = ?";
selectionArgs = new String[]{"application/x-rar-compressed", "text/html","audio/mpeg", "audio/ogg", "video/mp4","application/msword", "application/pdf", "application/vnd.ms-excel","application/vnd.openxmlformats-officedocument.wordprocessingml.document","application/vnd.openxmlformats-officedocument.spreadsheetml.sheet","text/plain","application/vnd.android.package-archive"};

额,很长,哈哈,后面再测试的过程中发现一个问题,那就是有一些文件(.docx .xls .xlsx .rar)按照mime_type 来查询的话无法加载出来。这就尴尬了,抓耳挠腮,搞了一下午,硬是没找着,并且马上要提测了,干脆骗测试,手机了没有这个文件?哈哈,显然不行,工作要紧。然后在查找资料的过程中发现了以为大牛的方法不错,可以解决我的这个难题https://blog.csdn.net/zocki33250/article/details/48112669,他的方案是在条件那个字段那里写一个数据库查询的语句

selection = "(" + MediaStore.Files.FileColumns.DATA + " LIKE '%.xls'" +" or " + MediaStore.Files.FileColumns.DATA + " LIKE '%.docx'" +" or " + MediaStore.Files.FileColumns.DATA + " LIKE '%.xlsx'" +" or " + MediaStore.Files.FileColumns.DATA + " LIKE '%.rar'" + ")";selectionArgs = null;

经过测试,完美解决,但是时间上又稍微慢了个1-2s,不过相对于之前的10s,已经快很多了。


三、总结

先写优点:
1、明显提高了查询的速度
2、个人认为该实现方案应该是比较好的(嘿嘿~)
缺点:
1、有局限性,需要知道所查询的文件的类型,然后再找到对应的mime_type
2、有些文件查询不出来,得利用其他方法,比如查询.xls等文件,如果加入该方法,查询速度明显降低,经过测试,如果这个方法里面的类型增多,那么该方案将没有啥有事,打开依然很慢。

四、写在最后

我这个实现的方法只为了实现而实现,灵活性可能降低了一些,若各位大神有什么好的建议,欢迎指正,交流

五、后记(测试优化)

之前我用的手机是小米手机,其他机型没有进行适配,后来经过测试发现,部分厂商的手机(华为、oppo)会出现apk文件扫描不到的情景,代码已在上面进行修改

六、疑问

各位看官大佬,我想问一个问题,为什么有些厂商的手机的有些文件(.xls、.rar etc.)无法根据mime_type进行扫描呢?contentprovider里面文件存储的mime_type不是唯一的吗?不是与文件类型一一对应的吗?

android手机文件快速扫描,并归类相关推荐

  1. android识别手机文件 快速扫描并优化加载速度

    一.最近在做一个需求,手机文件的快速扫描功能. 先附上效果图: 二.这边写了四种类型的文件识别,分别为音视频,图片,文件,并调取手机文件,这边分别用了四个Fragment,方便复制粘贴,用哪个粘哪个, ...

  2. 小程序影藏溢出的gif_如何在Android手机上快速实现视频转GIF动图呢?

    毫无疑问,Android是目前使用最广泛的手机系统.GIF很有趣,并且比视频占用更少的存储容量.本文将向您介绍如何在Android手机上快速转GIF动图的多种方法. [官网]万兴优转 - 顶尖音视频格 ...

  3. Android 信号查看,安卓Android手机怎么快速查看系统信号强度

    核心提示:我们能够在自己的Android手机中查看到目前所在网络的信号强度情况吗?在本篇教程中将会为你介绍安卓Android手机怎么快速查看系统信号强度! 手机最大的功能自然是打电话和发短信等基础性电 ...

  4. android开发2021,2021年高校邦Android手机软件快速开发App Inventor【2021秋】满分答案...

    2021年高校邦Android手机软件快速开发App Inventor[2021秋]满分答案 更多相关问题 <模仿:西方文学中的现实的再现>作者是:A.霍布斯B.阿多诺C.奥尔巴赫D.米勒 ...

  5. 将Android手机屏幕快速投影至WIN7的PC和投影仪

    在进行应用开发和展示的时候,经常需要将Android手机投影到PC屏幕或者投影仪上.豌豆荚或者91手机助手虽然能够通过USB将手机屏幕投影至PC,但是在手机上切换屏幕时,PC上相应的影像切换速度太慢, ...

  6. android 手机文件及文件夹目录详解

    adb shell ls -a -l 1.acct -系统回收站,误删除的系统文件恢复 2.cache -缓存 3.config-(计算机)配置 4.data-用户所有程序相关数据 anr -记录有关 ...

  7. Android手机文件及文件夹目录详解

    Android手机/模拟器文件夹目录详解 [前言] 我所使用的是Genymotion模拟器,这个模拟器真的有够快的和真机差不多,如果你也想用的话,下面是我下载安装的一些经验 http://blog.c ...

  8. 电脑上与android手机文件互传

    #在电脑上操作android手机目录文件 安装apk ./adb install *.apk 查看是否连接手机 ./adb devices 进入手机目录 ./adb shell 拷贝电脑文件 a.tx ...

  9. android手机 文件丢失,Android手机意外删除了文件恢复

    操作方法: 如果手机已启用云备份功能或使用第三方云备份软件,则可以登录手机上的云备份帐户,最后将数据同步到手机上. 可恢复的内容包括图片和文件,信息,地址簿. Android手机使用技巧: 1.由于A ...

最新文章

  1. Win10系统如何在防火墙里开放端口
  2. 学python培训到底能干嘛
  3. Java Web中的中文编码
  4. tableau使用_使用Tableau升级Kaplan-Meier曲线
  5. LintCode 600. 包裹黑色像素点的最小矩形(BFS)
  6. java day05【数组】
  7. c语言函数名称大全,C语言函数大全
  8. 深大uooc大学生心理健康章节答案第九章
  9. PyTorch 使用 TensorBoard 中的 writer.add_scalar 与 writer.add_scalars 的区别
  10. 分治回溯--Nqueen
  11. SILKY MIRACLE宣布奚梦瑶为品牌代言人
  12. Problem B. L04-02 一元二次方程的根(重点在于求虚根---初学简单版)
  13. 2023基于微信小程序的校园第二课堂活动报名系统+后台管理系统(Springboot+mysql)-JAVA.VUE(论文+开题报告+运行)
  14. 【面试】面试的时候,如何自我介绍?
  15. Matlab fplot函数详解
  16. github上能找到中文博主吗_Lyx的安装流程(windows10系统)及配置中文环境
  17. if or函数套用_Excel将IF函数和OR函数结合使用进行多条件的选择性判断
  18. oracle时间戳表达式,Oracle Timestamp类型
  19. 苹果x屏幕多少钱_iphone12系列屏幕维修多少钱 苹果iphone12维修价格表一览[多图]-手机资讯...
  20. 【ACWing】1064. 小国王

热门文章

  1. 百度智能云服务器BCC实例在线配置变更
  2. 批量修改文件名,图文教学,2分钟简单学会
  3. 基于MATLAB的差分方程战斗模型
  4. PDF电子签名申请与设置方法
  5. 在中信工作的那些日子
  6. 获取windows程序界面数据
  7. php移动端可拖动可视化,可视化编辑uniapp项目DIY拖拽
  8. cmake编译错误,将警告视为错误的解决方法
  9. windows2003 升级sp1,sp2 产品密匙无效
  10. 新能源产业写入2021年11省两会政府工作报告,大爆发在即!