FileObserver遞歸監(jiān)聽目錄(解決無(wú)法監(jiān)聽目錄的創(chuàng)建沾凄、刪除問(wèn)題)
主要內(nèi)容
為了解決Android媒體數(shù)據(jù)庫(kù)更新不及時(shí)的問(wèn)題岖沛,我想打算通過(guò)FileObserver監(jiān)聽SD卡根目錄下所有文件的變化,然后根據(jù)文件的變化對(duì)Android媒體數(shù)據(jù)庫(kù)進(jìn)行更新搭独。而FileObserver無(wú)法做到遞歸監(jiān)聽婴削。通過(guò)參考FileObserver 研究及其遞歸監(jiān)聽初步實(shí)現(xiàn)這篇博客,在其基礎(chǔ)上牙肝,主要解決了幾個(gè)問(wèn)題:
- 無(wú)法監(jiān)聽目錄的創(chuàng)建唉俗、刪除
- 開啟監(jiān)聽之后,新創(chuàng)建的目錄無(wú)法監(jiān)聽
- 冗余注冊(cè)監(jiān)聽的問(wèn)題
冗余注冊(cè)監(jiān)聽我是通過(guò)用ArrayMap鍵值對(duì)來(lái)解決的配椭,以監(jiān)聽目錄的絕對(duì)路徑作為key虫溜,以監(jiān)聽器作為value。(也可以使用ArraySet集合實(shí)現(xiàn))而開啟監(jiān)聽之后股缸,新創(chuàng)建的目錄無(wú)法監(jiān)聽的問(wèn)題則是通過(guò)監(jiān)聽FileObserver.CREATE事件衡楞,當(dāng)創(chuàng)建新目錄且該目錄還沒(méi)注冊(cè)監(jiān)聽時(shí),就注冊(cè)并啟動(dòng)監(jiān)聽敦姻。
接下來(lái)瘾境,干貨來(lái)了,代碼如下:
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)
{
// 遞歸監(jiān)聽目錄
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)
{
// 遞歸監(jiān)聽目錄
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);
}
}
}
}
總結(jié)
這算是一個(gè)比較好的遞歸監(jiān)聽解決方案镰惦,當(dāng)然還可以進(jìn)行優(yōu)化迷守,比如監(jiān)聽目錄的刪除事件,并取消該目錄的監(jiān)聽旺入。最后兑凿,吐槽一下,博客就是個(gè)人感想和收獲的總結(jié)茵瘾,到處抄來(lái)抄去沒(méi)什么意思礼华。看完別人的博客之后拗秘,我們應(yīng)該寫出自己的見解圣絮,提出更好的解決方案,而不是收藏聘殖、轉(zhuǎn)載和抄襲晨雳。最后,借鑒別人的東西奸腺,請(qǐng)注明出處餐禁。