sunyFS 2019-11-04 10:22 采纳率: 100%
浏览 473
已采纳

Android如何快速将1w+的文件进行排序(先文件夹后文件)

情景:目前在做一个文件夹管理器,用recyclerView加载1w+图片.防止OOM进行了分页加载,原理是对listFiles的数据集进行分页,先加载20个数据,到后几项时,在加载20;

需求:想对1w+图片的父文件夹(里面可能包含其他文件夹)进行 先文件夹后文件的排序,要求花费时间少.

之前测试:使用过 Arrays.sort对listFiles获取的数据集进行排序,但是耗时大概是1minute.用户体验不好.

一种是开始先对数据源排序(能实现但是耗时多),有没有耗时少的方法

 File[] files = new File(path).listFiles();//数据源
        //排序:先文件夹后文件 耗时少

        //分页加载
        LoadMore();

另一种是在分页中进行排序(未能实现)
在预加载的20项中,如果是为文件夹,就把该项放到前面中,这种方法可行耗时少,但是需要滑到文件夹项才可以,如果是在1w的后面的话就糟糕了.

钱包空了.见谅.就当交流交流吧,哈哈哈哈.

  • 写回答

2条回答 默认 最新

  • 王能 2019-11-05 15:20
    关注

    你肯定是哪个地方写错了,才1w个字符串而已,我创建了1w个10~50的空文件,排序总耗时1秒多(已在手机上测试2w条2秒多就排好了)

        public static void main(String[] args) {
            cretTestFile();
            File[] files = new File("/Users/cloudplug/Desktop/ft").listFiles();
            long t1 = System.currentTimeMillis();
            Arrays.sort(files, new Comparator<File>() {
                @Override
                public int compare(File lhs, File rhs) {
                    //返回负数表示o1 小于o2,返回0 表示o1和o2相等,返回正数表示o1大于o2。 
                    boolean l1 = lhs.isDirectory();
                    boolean l2 = rhs.isDirectory();
                    if (l1 && !l2)
                        return -1;
                    else if (!l1 && l2)
                        return 1;
                    else {
                        return lhs.getName().compareTo(rhs.getName());
                    }
                }
            });
            long t2 = System.currentTimeMillis();
            System.out.println(t2 - t1);
        }
    
        private static void cretTestFile() {
            File root = new File("/Users/cloudplug/Desktop/ft");
            if (root.exists()) {
                return;
            }
            root.mkdir();
            for (int i = 0; i < 10000; i++) {
                File child = new File(root, getSt() + ".txt");
                child.mkdir();
            }
        }
    
        private static String getSt() {
            StringBuilder st = new StringBuilder();
            int length = (int) (Math.random() * 40) + 10;
            for (int i = 0; i < length; i++) {
                st.append(String.valueOf((char) (Math.random() * 26 + 65)));
            }
            return st.toString();
        }
    

    还有,加载图片又不需要分页,没显示的东西不会加载到内存,这是RecyclerView、ListView等可回收布局的基本特性,你可以参考所有本地图片浏览的app,从没见过分页这一说

    建议发一下原代码看看哪里写错了

    看你的描述对这2个功能完全理解错了,建议如下

    1.排序这种东西,无论什么算法只要不写错,几万条数据只是眨眼的功夫:

    优化一下不用file,直接获取文件名,1w文件排序仅仅是几十毫秒而已:

            long t3 = System.currentTimeMillis();
            String[] files = new File("/Users/cloudplug/Desktop/ft").list();
            System.out.println(files.length);
            System.out.println(files[10]);
            Arrays.sort(files, new Comparator<String>() {
                @Override
                public int compare(String s1, String s2) {
                    //返回负数表示o1 小于o2,返回0 表示o1和o2相等,返回正数表示o1大于o2。
                    return s1.compareTo(s2);
                }
            });
            long t4 = System.currentTimeMillis();
            System.out.println(t4 - t3);
    

    2.建议深入理解一下app端复用机制的特性,理论上加载数据是没有上限的,大致原理如下:

    假设有1亿条数据(不考虑数组大小),页面上单页可以展示10条。现在:无论你滑到哪一个位置,占内存的永远都是当前展示的10条数据(暂时不考虑三级缓存、预加载)。
    如你现在正在浏览第10000张图片,那么在内存中只会有10000-10009这10张图片,其他图片依然还是在磁盘里躺着,当你往下滑的时候,上面的图片就会被回收,再加载下面的图片,以此往复内存永远不会增长(暂时不考虑三级缓存、预加载)。
    为什么会引起oom:
    1.你使用了嵌套,类似RecyclerView、ScrollView、listview...多个可滑动的控件互相套用。
    解决方式:将套用控件删掉只留一个,使用多条目或者headerfooter的方式去除嵌套。
    2.你没有及时释放或压缩图片,图片是很占用内存的,所以应及时释放或者压缩。
    解决方式:建议直接使用第三方图片加载框架:glide、Picasso等,这些第三方已经处理了所有的情况,只要不是嵌套不会有问题。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 求学软件的前人们指明方向🥺
  • ¥50 如何增强飞上天的树莓派的热点信号强度,以使得笔记本可以在地面实现远程桌面连接
  • ¥15 MCNP里如何定义多个源?
  • ¥20 双层网络上信息-疾病传播
  • ¥50 paddlepaddle pinn
  • ¥20 idea运行测试代码报错问题
  • ¥15 网络监控:网络故障告警通知
  • ¥15 django项目运行报编码错误
  • ¥15 STM32驱动继电器
  • ¥15 Windows server update services