In my application, I have different components, which monitor the particular file in sdcard using FileObservers. So there are two instances of File Observer which observe a single file, say abc.xml for all events.
FileObserver fo1 = new FileObserver(new File("/sdcard/abc.xml"));
fo1.startWatching();
FileObserver fo2 = new FileObserver(new File("/sdcard/abc.xml"));
fo2.startWatching();
They both are registered for different events. My problem is when both of the file observers are watching in parallel, I am missing the calls to onEvent() of "fo1".
Is this a limitation of Android system? What are the ways to overcome this problem?
Late but maybe helpful for others: It's a bug in Android - the issue is reported here.
Since this was making me tear my hair out, I wrote a drop-in replacement for FileObserver which works around the issue by maintaining a master-list of FileObservers. Replacing all FileObservers in an application with this FixedFileObserver should result in the expected behaviour. (health warning: I did not test it very extensively in all corner cases but it works for me)
FixedFileObserver.java
package com.fimagena.filepicker.backend;
import android.os.FileObserver;
import java.io.File;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
public abstract class FixedFileObserver {
private final static HashMap<File, Set<FixedFileObserver>> sObserverLists = new HashMap<>();
private FileObserver mObserver;
private final File mRootPath;
private final int mMask;
public FixedFileObserver(String path) {this(path, FileObserver.ALL_EVENTS);}
public FixedFileObserver(String path, int mask) {
mRootPath = new File(path);
mMask = mask;
}
public abstract void onEvent(int event, String path);
public void startWatching() {
synchronized (sObserverLists) {
if (!sObserverLists.containsKey(mRootPath)) sObserverLists.put(mRootPath, new HashSet<FixedFileObserver>());
final Set<FixedFileObserver> fixedObservers = sObserverLists.get(mRootPath);
mObserver = fixedObservers.size() > 0 ? fixedObservers.iterator().next().mObserver : new FileObserver(mRootPath.getPath()) {
@Override public void onEvent(int event, String path) {
for (FixedFileObserver fixedObserver : fixedObservers)
if ((event & fixedObserver.mMask) != 0) fixedObserver.onEvent(event, path);
}};
mObserver.startWatching();
fixedObservers.add(this);
}
}
public void stopWatching() {
synchronized (sObserverLists) {
Set<FixedFileObserver> fixedObservers = sObserverLists.get(mRootPath);
if ((fixedObservers == null) || (mObserver == null)) return;
fixedObservers.remove(this);
if (fixedObservers.size() == 0) mObserver.stopWatching();
mObserver = null;
}
}
protected void finalize() {stopWatching();}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With