Android: FileObserver monitors only top directory
Asked Answered
P

2

13

According to the documentation,

"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."

My code goes like,

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

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

However, the onEvent() is triggering only when a file is changed in the /mnt/sdcard/. If I create a file in /mnt/sdcard/downloads/, the method is not getting fired.

Is there any problem with the code?

Putrescent answered 8/5, 2013 at 18:47 Comment(0)
V
8

According to the documentation

The documentation is incorrect, as is noted in this issue.

Is there any problem with the code?

No, but FileObserver is not recursive, despite the documentation to the contrary.

Vindicable answered 8/5, 2013 at 20:21 Comment(2)
FYI, the documentation as quoted above no longer mentions being recursive as it once mistakenly did, though it would be nice if it explicitly said it was not recursive - something the Linux man page for the underlying inotify does add in a note at the end.Tonitonia
What if I want to monitor the partition for storage changes ? Is there a way to do it?Sedum
F
37

There is an open-source RecursiveFileObserver that works just as the normal FileObserver should ... I am using it currently it is what it is named , it acts as a FileObserver that is recursive for all directories beneath the directory you chose ...

Here is it :

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);
    } 

}
}

Make a new class in your app and copy this code to it , and use it as you like ! Vote up if you find this helpful !

Fatalism answered 25/6, 2013 at 15:25 Comment(4)
Be careful: This is not completely recursive as it will not start watching automatically any newly created folder, nor will it stop watching folders that are moved out from the tree... Since this is licensed GPLv2, anybody solving these problems based on the current implementation should share back the code.Unclothe
I used the code and it says "Can't create handler in a thread if Looper.create() is not called" :/Unvoiced
Please give credit/reference to the original source, I think that is: gist.github.com/gitanuj/888ef7592be1d3f617f6Postgraduate
@yoav-feuerstein, just a remark: Not sure why the original package declaration had been omitted in this answer (and unfortunately, the import statements, too). However, the class seems to be borrowed from com.owncloud.android.utils, as another answer, which is also referring to this one over here, points out. The code similarity appears to be higher than to that gist.Anklebone
V
8

According to the documentation

The documentation is incorrect, as is noted in this issue.

Is there any problem with the code?

No, but FileObserver is not recursive, despite the documentation to the contrary.

Vindicable answered 8/5, 2013 at 20:21 Comment(2)
FYI, the documentation as quoted above no longer mentions being recursive as it once mistakenly did, though it would be nice if it explicitly said it was not recursive - something the Linux man page for the underlying inotify does add in a note at the end.Tonitonia
What if I want to monitor the partition for storage changes ? Is there a way to do it?Sedum

© 2022 - 2024 — McMap. All rights reserved.