一、概述
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 void startWatching(String path){
MyFileObserver observer = new MyFileObserver(path)
observer.startWatching();
synchronized(ob_lock){
// TODO 這裏去執行程序中需要枷鎖進行同步的操作,不要將startWatching放在業務邏輯鎖中,防止死鎖。
}
}
}
五、FileObserver總結
文件操作相關的開發中,經常會用到FileObserver對文件的監控操作,從而去實現當文件有變化時,程序及時進行UI邏輯反饋給用戶的能力,上面我列出了自己在使用過程中的一些經驗和總結,如果有遺留的思路或者問題,歡迎進行留言反饋。