【问题标题】:Android: FileObserver monitors only top directoryAndroid:FileObserver 仅监控顶层目录
【发布时间】:2013-05-08 18:47:26
【问题描述】:

根据文档,

"Each FileObserver instance monitors a single file or directory. If a directory is monitored, 
events will be triggered for all files and subdirectories inside the monitored directory."

我的代码是这样的,

    FileObserver fobsv = new FileObserver("/mnt/sdcard/") {

    @Override
    public void onEvent(int event, String path) {
        System.out.println(event+"    "+path);
    }
    };
    fobsv.startWatching();

但是,onEvent() 仅在 /mnt/sdcard/ 中的文件更改时触发。如果我在 /mnt/sdcard/downloads/ 中创建文件,该方法不会被触发。

代码有问题吗?

【问题讨论】:

    标签: android android-sdcard fileobserver


    【解决方案1】:

    有一个开源的RecursiveFileObserver 可以像普通的FileObserver 一样工作......我目前正在使用它,它就是它的名字,它作为一个 FileObserver,对下面的所有目录都是递归的您选择的目录...

    这里是:

    public class RecursiveFileObserver extends FileObserver {
    
    public static int CHANGES_ONLY = CLOSE_WRITE | MOVE_SELF | MOVED_FROM;
    
    List<SingleFileObserver> mObservers;
    String mPath;
    int mMask;
    
    public RecursiveFileObserver(String path) {
        this(path, ALL_EVENTS);
    }
    
    public RecursiveFileObserver(String path, int mask) {
        super(path, mask);
        mPath = path;
        mMask = mask;
    }
    
    @Override
    public void startWatching() {
        if (mObservers != null) return;
        mObservers = new ArrayList<SingleFileObserver>();
        Stack<String> stack = new Stack<String>();
        stack.push(mPath);
    
        while (!stack.empty()) {
            String parent = stack.pop();
            mObservers.add(new SingleFileObserver(parent, mMask));
            File path = new File(parent);
            File[] files = path.listFiles();
            if (files == null) continue;
            for (int i = 0; i < files.length; ++i) {
                if (files[i].isDirectory() && !files[i].getName().equals(".")
                    && !files[i].getName().equals("..")) {
                    stack.push(files[i].getPath());
                }
            }
        }
        for (int i = 0; i < mObservers.size(); i++)
            mObservers.get(i).startWatching();
    }
    
    @Override
    public void stopWatching() {
        if (mObservers == null) return;
    
        for (int i = 0; i < mObservers.size(); ++i)
            mObservers.get(i).stopWatching();
    
        mObservers.clear();
        mObservers = null;
    }
    
    @Override
    public void onEvent(int event, String path) {
    
    }
    
    private class SingleFileObserver extends FileObserver {
        private String mPath;
    
        public SingleFileObserver(String path, int mask) {
            super(path, mask);
            mPath = path;
        }
    
        @Override
        public void onEvent(int event, String path) {
            String newPath = mPath + "/" + path;
            RecursiveFileObserver.this.onEvent(event, newPath);
        } 
    
    }
    }
    

    在您的应用程序中创建一个新类并将此代码复制到其中,然后随意使用它! 如果您觉得这有帮助,请投票!

    【讨论】:

    • 小心:这不是完全递归的,因为它不会自动开始监视任何新创建的文件夹,也不会停止监视从树中移出的文件夹...由于这是许可的 GPLv2,任何基于当前实现解决这些问题的人都应该分享代码。
    • 我使用了代码,它说“如果未调用 Looper.create(),则无法在线程中创建处理程序”:/
    • 请注明/参考原始出处,我认为是:gist.github.com/gitanuj/888ef7592be1d3f617f6
    • @yoav-feuerstein,只是一个评论:不知道为什么在这个答案中省略了原始包声明(不幸的是,导入语句也是如此)。然而,这个类似乎是从com.owncloud.android.utils 借来的,正如another answer 所指出的,这里也指这个类。代码相似度似乎高于该要点。
    【解决方案2】:

    根据文档

    文档不正确,如this issue 中所述。

    代码有问题吗?

    不,但FileObserver 不是递归的,尽管文档相反。

    【讨论】:

    • 仅供参考,上面引用的文档不再像曾经错误地那样提及递归,尽管如果它明确表示它不是递归的会很好——底层 inotify 的 Linux 手册页确实如此在末尾添加注释。
    • 如果我想监控分区的存储变化怎么办?有办法吗?