如何在安卓上优雅的搜索文件,解决The content of the adapter has changed but ListView did not receive a notification报错

码字辛苦!转载请注明出处!

我们知道,在安卓上运行JAVA有严格的内存限制,不能像PC上那样肆无忌惮的使用递归和多线程,否则~

OOM,经典不~

那么,如何在安卓上优雅搜索文件呢?

关键点就在于:

1、取代递归

2、适时终止上一个搜索线程

3、在主线程中更新List和View

4、避免线程中Activity对象造成的内存泄漏

——那我们把需要搜索的文件目录记录下来循环遍历,在回调时检测Activity生命周期,并进行线程切换,问题不就解决了嘛~

话不多说,上代码:


    //搜索文件线程
    private Thread t_searchFile;

    public interface SearchFileListener {
        void gotOne(File file);

        void onFinished(List<File> searchedFiles);
    }

    //搜索文件
    public List<File> searchFile(final Activity activity, final String filePath,
                                 final String fileName, final SearchFileListener searchFileListener) {

        //终止上一个搜索线程(如果有)
        stopSearching();

        final List<File> searchedFiles = new ArrayList<>();
        if (TextUtils.isEmpty(fileName) || TextUtils.isEmpty(filePath)) {
            return searchedFiles;
        }
        t_searchFile = new Thread() {
            @Override
            public void run() {
                super.run();

                //不使用递归,而是将需要扫描的文件目录记录下来
                List<File> waitForSearchFilePath = new ArrayList<>();
                waitForSearchFilePath.add(new File(filePath));

                while (waitForSearchFilePath.size() > 0 && !isInterrupted() &&
                        //所有循环均检测Activity生命周期,以防内存泄漏
                        !activityIsDestroyed(activity)) {
                    File[] files = waitForSearchFilePath.get(0).listFiles();
                    if (files != null) {
                        for (int i = 0; i < files.length; i++) {
                            if (isInterrupted() && activityIsDestroyed(activity)) {
                                break;
                            }
                            final File temp = files[i];

                            //过滤掉没有读写权限的文件,以防权限异常崩溃
                            if (temp.canRead() && temp.canWrite()) {

                                //全部转换为小写再匹配,以使搜索结果不区分大小写
                                if (temp.getName().toLowerCase().contains(fileName.toLowerCase())) {

                                    //当Activity生命周期已经结束时,终止搜索
                                    if (activityIsDestroyed(activity)) {
                                        break;
                                    }

                                    //将符合条件的项目添加到链表,并在主线程回调以便刷新页面
                                    activity.runOnUiThread(new Runnable() {
                                        @Override
                                        public void run() {
                                            searchedFiles.add(temp);
                                            if (searchFileListener != null) {
                                                searchFileListener.gotOne(temp);
                                            }
                                        }
                                    });
                                }
                                if (temp.isDirectory()) {

                                    //将子目录添加到待扫描链表,替代递归
                                    waitForSearchFilePath.add(temp);
                                }
                            }
                        }
                    }

                    //完成当前目录扫描,移除链表
                    waitForSearchFilePath.remove(0);
                }
                if (!activityIsDestroyed(activity) && !isInterrupted()) {
                    activity.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            if (searchFileListener != null) {
                                searchFileListener.onFinished(searchedFiles);
                            }
                        }
                    });
                }
            }
        };
        t_searchFile.start();
        return searchedFiles;
    }

    //终止搜索线程
    public void stopSearching() {
        if (t_searchFile != null) {
            t_searchFile.interrupt();
        }
    }

    //检测Activity生命周期
    private boolean activityIsDestroyed(Activity activity) {
        return activity == null || activity.isFinishing() || activity.isDestroyed();
    }

使用上述方法,实测该线程的内存(不含已检出的文件List)只有不到3K,OOM问题完美解决~

最后,如果您觉得博主的文章对您有帮助的话,不妨给博主打个小红包呗~

猜你喜欢

转载自blog.csdn.net/u014653815/article/details/88988913