FileObserver递归监听目录(解决无法监听目录的创建、删除问题)
主要内容
为了解决Android媒体数据库更新不及时的问题,我想打算通过FileObserver监听SD卡根目录下所有文件的变化,然后根据文件的变化对Android媒体数据库进行更新。而FileObserver无法做到递归监听。通过参考FileObserver 研究及其递归监听初步实现这篇博客,在其基础上,主要解决了几个问题:
- 无法监听目录的创建、删除
- 开启监听之后,新创建的目录无法监听
- 冗余注册监听的问题
冗余注册监听我是通过用ArrayMap键值对来解决的,以监听目录的绝对路径作为key,以监听器作为value。(也可以使用ArraySet集合实现)而开启监听之后,新创建的目录无法监听的问题则是通过监听FileObserver.CREATE事件,当创建新目录且该目录还没注册监听时,就注册并启动监听。
接下来,干货来了,代码如下:
public class RecursiveFileObserver extends FileObserver
{
Map<String, 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 ArrayMap<>();
Stack stack = new Stack();
stack.push(mPath);
while (!stack.isEmpty())
{
String temp = (String) stack.pop();
mObservers.put(temp, new SingleFileObserver(temp, mMask));
File path = new File(temp);
File[] files = path.listFiles();
if (null == files)
continue;
for (File f: files)
{
// 递归监听目录
if (f.isDirectory() && !f.getName().equals(".") && !f.getName()
.equals(".."))
{
stack.push(f.getAbsolutePath());
}
}
}
Iterator<String> iterator = mObservers.keySet().iterator();
while (iterator.hasNext()) {
String key = iterator.next();
mObservers.get(key).startWatching();
}
}
@Override public void stopWatching()
{
if (mObservers == null)
return ;
Iterator<String> iterator = mObservers.keySet().iterator();
while (iterator.hasNext()) {
String key = iterator.next();
mObservers.get(key).stopWatching();
}
mObservers.clear();
mObservers = null;
}
@Override public void onEvent(int event, String path)
{
int el = event & FileObserver.ALL_EVENTS;
switch (el)
{
case FileObserver.ATTRIB:
Log.i("RecursiveFileObserver", "ATTRIB: " + path);
break;
case FileObserver.CREATE:
File file = new File(path);
if(file.isDirectory()) {
Stack stack = new Stack();
stack.push(path);
while (!stack.isEmpty())
{
String temp = (String) stack.pop();
if(mObservers.containsKey(temp)) {
continue;
} else {
SingleFileObserver sfo = new SingleFileObserver(temp, mMask);
sfo.startWatching();
mObservers.put(temp, sfo);
}
File tempPath = new File(temp);
File[] files = tempPath.listFiles();
if (null == files)
continue;
for (File f: files)
{
// 递归监听目录
if (f.isDirectory() && !f.getName().equals(".") && !f.getName()
.equals(".."))
{
stack.push(f.getAbsolutePath());
}
}
}
}
Log.i("RecursiveFileObserver", "CREATE: " + path);
break;
case FileObserver.DELETE:
Log.i("RecursiveFileObserver", "DELETE: " + path);
break;
case FileObserver.DELETE_SELF:
Log.i("RecursiveFileObserver", "DELETE_SELF: " + path);
break;
case FileObserver.MODIFY:
Log.i("RecursiveFileObserver", "MODIFY: " + path);
break;
case FileObserver.MOVE_SELF:
Log.i("RecursiveFileObserver", "MOVE_SELF: " + path);
break;
case FileObserver.MOVED_FROM:
Log.i("RecursiveFileObserver", "MOVED_FROM: " + path);
break;
case FileObserver.MOVED_TO:
Log.i("RecursiveFileObserver", "MOVED_TO: " + path);
break;
}
}
class SingleFileObserver extends FileObserver
{
String mPath;
public SingleFileObserver(String path) {
this(path, ALL_EVENTS);
mPath = path;
}
public SingleFileObserver(String path, int mask)
{
super(path, mask);
mPath = path;
}
@Override public void onEvent(int event, String path)
{
if(path != null) {
String newPath = mPath + "/" + path;
RecursiveFileObserver.this.onEvent(event, newPath);
}
}
}
}
总结
这算是一个比较好的递归监听解决方案,当然还可以进行优化,比如监听目录的删除事件,并取消该目录的监听。最后,吐槽一下,博客就是个人感想和收获的总结,到处抄来抄去没什么意思。看完别人的博客之后,我们应该写出自己的见解,提出更好的解决方案,而不是收藏、转载和抄袭。最后,借鉴别人的东西,请注明出处。
网友评论