一、概述
FileObserver主要用來提供對文件或者文件夾的監(jiān)控,一個FileObserver實例監(jiān)控一個文件,能夠監(jiān)控的文件或者文件夾的event type包括下表中的幾種。
| 類型值 | 類型名稱 | 含義 |
|---|---|---|
| 1 | ACCESS | 從文件中讀取數(shù)據(jù) |
| 2 | MODIFY | 從文件中編輯數(shù)據(jù) |
| 4 | ATTRIB | 文件元數(shù)據(jù)(權(quán)限,擁有者,時間戳)被明確改變 |
| 8 | CLOSE_WRITE | 有人打開文件或者目錄進行書寫,并且關(guān)閉它 |
| 16 | CLOSE_NOWEITTE | 有人打開文件或者目錄沒有編輯,并且關(guān)閉它 |
| 32 | OPEN | 一個文件或者目錄被打開 |
| 64 | MOVE_FROM | 一個文件或者子目錄從被監(jiān)控目錄被移出 |
| 128 | MOVE_TO | 一個文件或者子目錄被移入到被監(jiān)控的目錄 |
| 256 | CREATE | 一個文件或者子目錄在被監(jiān)控的目錄下被創(chuàng)建 |
| 512 | DELETE | 文件從監(jiān)控目錄被刪除 |
| 1024 | DELETE_SELF | 監(jiān)控的文件或者目錄被刪除,監(jiān)控停止 |
| 2048 | MOVE_SELF | 監(jiān)控的文件或者目錄被移動,監(jiān)控繼續(xù) |
另外,在調(diào)試的過程中,FileObserver的onEvent會返回未明確定義的event type,經(jīng)過調(diào)試,對應(yīng)的含義如下表。
| 類型值 | 含義 |
|---|---|
| 1073742080 | “文件夾”的創(chuàng)建(Create)操作 |
| 1073742336 | “文件夾”的刪除(Delete)操作 |
| 1073741888 | “文件夾”的移出(MOVE_FROM) 操作 |
| 1073741952 | “文件夾”的移入(MOVE_TO) 操作 |
| 32768 | “文件夾” 的打開操作 (OPEN) 操作 |
如果發(fā)現(xiàn)新的類型,后期會進行完善。
二、FileObserver的使用
FileObserver的API相對簡單,可以繼承FileObserver實現(xiàn)自定義的MyFileObserver,目的是監(jiān)控onEvent回調(diào),然后執(zhí)行startWatching啟動監(jiān)控,在需要停止監(jiān)控的時候執(zhí)行stopWatching。
三、FileObserver收不到onEvent回調(diào)
如果在開發(fā)的過程中,遇到onEvent無法接收的問題,先確認(rèn)對以下幾種可能原因進行排除。
- FileObserver對象實例被回收 (思路:通過放在Application中進行測試)
- 初始化順序問題 (思路:盡早的對FileObserver進行初始化)
- 沒有讀寫文件權(quán)限問題 (思路: 文件監(jiān)控需要文件讀寫權(quán)限)
- onEvent中做復(fù)雜操作 (思路: 先跑通,再實現(xiàn)邏輯)
- 妨礙 inotify的可能性
- 同一個進程中,如果有兩個不同的FileObserver同時監(jiān)控一個Path,只有后調(diào)用startWatching的FileObserver能夠收到onEvent回調(diào)。(Android系統(tǒng)Bug)
我在開發(fā)的過程中,最終是最后一點導(dǎo)致的,這是Android framework的Bug,Android系統(tǒng)Bug地址,解決方案在地址中有提供。
四、FileObserver使用注意事項
因為FileObserver的startWatching和stopWatching都存在加鎖操作。拿startWatching源碼舉例。
public int startWatching(String path, int mask, FileObserver observer) {
int wfd = startWatching(m_fd, path, mask);
Integer i = new Integer(wfd);
if (wfd >= 0) {
synchronized (m_observers) {
m_observers.put(i, new WeakReference(observer));
}
}
return i;
}
其中有m_observers對象鎖,所有在我們調(diào)用MyFileObserver的 startWatching時,盡量不要放在自己實現(xiàn)的對象鎖中實現(xiàn),可能會引發(fā)死鎖操作,從而導(dǎo)致ANR。思路如下:
public class MyFileObserver extends FileObserver{
@Override
public void onEvent(int event0, String path) {
// TODO 處理自己的業(yè)務(wù)邏輯
}
}
public class FileObserverTest{
private static final Object ob_lock = new Object();
public void startWatching(String path){
MyFileObserver observer = new MyFileObserver(path)
observer.startWatching();
synchronized(ob_lock){
// TODO 這里去執(zhí)行程序中需要枷鎖進行同步的操作,不要將startWatching放在業(yè)務(wù)邏輯鎖中,防止死鎖。
}
}
}
五、FileObserver總結(jié)
文件操作相關(guān)的開發(fā)中,經(jīng)常會用到FileObserver對文件的監(jiān)控操作,從而去實現(xiàn)當(dāng)文件有變化時,程序及時進行UI邏輯反饋給用戶的能力,上面我列出了自己在使用過程中的一些經(jīng)驗和總結(jié),如果有遺留的思路或者問題,歡迎進行留言反饋。