FileObserver檔案監聽
一、概述
FileObserver主要用來提供對檔案或者資料夾的監控,一個FileObserver例項監控一個檔案,能夠監控的檔案或者資料夾的event type
包括下表中的幾種。
型別值 | 型別名稱 | 含義 |
---|---|---|
1 | ACCESS | 從檔案中讀取資料 |
2 | MODIFY | 從檔案中編輯資料 |
4 | ATTRIB | 檔案元資料(許可權,擁有者,時間戳)被明確改變 |
8 | CLOSE_WRITE | 有人開啟檔案或者目錄進行書寫,並且關閉它 |
16 | CLOSE_NOWEITTE | 有人開啟檔案或者目錄沒有編輯,並且關閉它 |
32 | OPEN | 一個檔案或者目錄被開啟 |
64 | MOVE_FROM | 一個檔案或者子目錄從被監控目錄被移出 |
128 | MOVE_TO | 一個檔案或者子目錄被移入到被監控的目錄 |
256 | CREATE | 一個檔案或者子目錄在被監控的目錄下被建立 |
512 | DELETE | 檔案從監控目錄被刪除 |
1024 | DELETE_SELF | 監控的檔案或者目錄被刪除,監控停止 |
2048 | MOVE_SELF | 監控的檔案或者目錄被移動,監控繼續 |
另外,在除錯的過程中,FileObserver
的onEvent
會返回未明確定義的event type
,經過除錯,對應的含義如下表。
型別值 | 含義 |
---|---|
1073742080 | “資料夾”的建立(Create)操作 |
1073742336 | “資料夾”的刪除(Delete)操作 |
1073741888 | “資料夾”的移出(MOVE_FROM) 操作 |
1073741952 | “資料夾”的移入(MOVE_TO) 操作 |
32768 | “資料夾” 的開啟操作 (OPEN) 操作 |
如果發現新的型別,後期會進行完善。
二、FileObserver的使用
FileObserver
的API相對簡單,可以繼承FileObserver
實現自定義的MyFileObserver
,目的是監控onEvent
回撥,然後執行startWatching
啟動監控,在需要停止監控的時候執行stopWatching
。
三、FileObserver收不到onEvent回撥
如果在開發的過程中,遇到onEvent
無法接收的問題,先確認對以下幾種可能原因進行排除。
- FileObserver物件例項被回收 (思路:通過放在Application中進行測試)
- 初始化順序問題 (思路:儘早的對FileObserver進行初始化)
- 沒有讀寫檔案許可權問題 (思路: 檔案監控需要檔案讀寫許可權)
- onEvent中做複雜操作 (思路: 先跑通,再實現邏輯)
- 妨礙 inotify的可能性
- 同一個程序中,如果有兩個不同的FileObserver同時監控一個Path,只有後呼叫startWatching的FileObserver能夠收到onEvent回撥。(Android系統Bug)
我在開發的過程中,最終是最後一點導致的,這是Android framework的Bug,Android系統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
物件鎖,所有在我們呼叫MyFileObserver
的startWatching
時,儘量不要放在自己實現的物件鎖中實現,可能會引發死鎖操作,從而導致ANR。思路如下:
public class MyFileObserver extends FileObserver{ @Override public void onEvent(int event0, String path) { // TODO 處理自己的業務邏輯 } } public class FileObserverTest{ private static final Object ob_lock = new Object(); public voidstartWatching(String path){ MyFileObserver observer = new MyFileObserver(path) observer.startWatching(); synchronized(ob_lock){ // TODO 這裡去執行程式中需要枷鎖進行同步的操作,不要將startWatching放在業務邏輯鎖中,防止死鎖。 } } }
五、FileObserver總結
檔案操作相關的開發中,經常會用到FileObserver對檔案的監控操作,從而去實現當檔案有變化時,程式及時進行UI邏輯反饋給使用者的能力,上面我列出了自己在使用過程中的一些經驗和總結,如果有遺留的思路或者問題,歡迎進行留言反饋。