Recently I have a requirement to monitor the files and directories under the directory. I checked that there is a class on Android: fileobserver. The usage and restrictions are briefly described below.
Android. OS. fileobserver
Monitors files (using inotify) to fire an event after files are accessed or changed by any process on the device (including this one ). fileobserver is an abstract class; subclasses must implement the event handler onevent (INT, string ).
Each fileobserver instance monitors a single file or directory. If a directory is monitored, events will be triggered for all files and subdirectories inside the monitored directory.
An event mask is used to specify which changes or actions to report. Event Type constants are used to describe the possible changes in the event mask as well as what actually happened in event callbacks.
The fileobserver class is a listener that monitors file access, creation, modification, deletion, and movement operations. It is based on Linux inotify.
Fileobserver is an abstract class that must be inherited before it can be used. Each fileobserver object listens to a single file or folder. If a folder is monitored,
The changes to all files and cascading subdirectories in the folder will trigger the listening event.
In fact, tests do not support recursion. For file changes in the subdirectory of the listening directory, the fileobserver object cannot receive event callbacks,
No Event Callback is received when the sub-directories of the listening directory are changed. The reason is determined by the inotify mechanism of Linux. The fileobserver Based on inotify naturally does not support recursive listening.
1. Overview
Fileobserver is an abstract class and must be inherited before it can be used.
Event types that can be monitored:
Access: the object is accessed.
Modify: The file is modified.
Attrib: file attributes are modified, such as chmod, chown, and touch.
Close_write: The writable file is closed.
Close_nowrite: the file cannot be written and is closed.
Open: The file is open.
Moved_from: The file is removed, such as mV.
Moved_to: The file is moved, such as mV and CP.
Create: Create a new file
Delete: The file is deleted, such as RM.
Delete_self: indicates that an executable file deletes itself during execution.
Move_self: indicates that an executable file moves itself during execution.
Close: The file is closed, equivalent to (in_close_write | in_close_nowrite)
All_events: includes all the above events
You can go to SDK develop for more details.
1. Create a directory listener
Class myfileobserver extends fileobserver {// This constructor listens to all events by default. If the super (string, INT) constructor is used, the int parameter is the event type to be monitored. // To prevent nested message calls, we recommend that you use super (string, INT) to create monitoring message values as needed public myfileobserver (string path) {super (path, fileobserver. close_write | fileobserver. create | fileobserver. delete | fileobserver. delete_self); // super (path, fileobserver. all_events) ;}@ overridepublic void onevent (INT event, string path) {synchronized (mutex) {// note that the event value is the same as 0x40000000 or the previous value, therefore, when case is required, you must first perform & fileobserver. all_eventsint El = event & fileo Bserver. all_events; log. I (TAG, "onevent event:" + EL + "Path:" + path); Switch (EL) {// todo all the listening event types in case fileobserver. XX static properties // if you want to perform more operations in onevent, it is best to use a thread to avoid blocking the receipt of subsequent events. // Try {// handler. obtainmessage (El, PATH ). sendtotarget (); //} catch (exception e) {// log. E (TAG, "monitor fileobserver. onevent error: "+ E );//}}}}}};
Use thread processing:
Private handler = NULL;
Private handlerthread th = NULL;
Th = new handlerthread ("sectionstorage ");
Th. Start ();
Handler = new handler (Th. getlooper (), callback );
Fobs = new myfileobserver (Root );
Message Processing:
Handler.Callback callback = new Handler.Callback() {@Overridepublic boolean handleMessage(Message msg) {Log.i(TAG, "callback msg.what=" + msg.what + " msg.obj:" + msg.obj);synchronized (mutex) {try {switch (msg.what) {case FileObserver.CLOSE_WRITE:onFileWriteClosed((String) msg.obj);break;case FileObserver.CREATE:onFileCreate((String) msg.obj);break;case FileObserver.DELETE:onFileDeleted((String) msg.obj);break;case FileObserver.DELETE_SELF:onRootDeleted();break;}} catch (Throwable e) {Log.e(TAG, "handleMessage error:" + e);}}}};
2. Set a listener for the Directory
Myfileobserver listener = new myfileobserver ("directory ");
// Start listening
Listener. startwatching ();
/*
* Perform some operations here, such as creating a directory or something.
*/
// Stop the listener
Listener. stopwatching ();
2. For the implementation code of recursive listening, refer to here:
Https://code.google.com/p/collimator/source/browse/trunk/src/com/toraleap/collimator/util/RecursiveFileObserver.java? Spec = svn22 & R = 22
The excerpt is as follows:
To listen to changes in the entire file system, we must implement this recursive listener. What should we do? First, let's look at how we use inotify to implement recursive listening,
The search result shows everything, recursively calling inotify for each subdirectory. That is to say, in Android, You have to traverse the directory tree to create a series
The fileobserver object is stupid. I was worried that this would have a huge impact on the system's efficiency, but everyone was doing this,
I also wrote the following recursivefileobserver class based on the principle of true knowledge:
========================================================== ========================================================== ==========================================
However, after compilation, I found a problem. My code is as follows: (I modified the compilation error and copied the code from it)
package com.test.fileobserver;import java.io.File;import java.util.ArrayList;import java.util.List;import java.util.Stack;import android.os.FileObserver;import android.util.Log;@SuppressWarnings(value = { "rawtypes", "unchecked" })public class RecursiveFileObserver extends FileObserver {/** Only modification events */public static int CHANGES_ONLY = CREATE | DELETE | CLOSE_WRITE| DELETE_SELF | MOVE_SELF | MOVED_FROM | MOVED_TO;List 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;}@Overridepublic void startWatching() {if (mObservers != null)return;mObservers = new ArrayList();Stack stack = new Stack();stack.push(mPath);while (!stack.isEmpty()) {String parent = (String)stack.pop();mObservers.add(new SingleFileObserver(parent, mMask));File path = new File(parent);File[] files = path.listFiles();if (null == files)continue;for (File f : files) {if (f.isDirectory() && !f.getName().equals(".")&& !f.getName().equals("..")) {stack.push(f.getPath());}}}for (int i = 0; i < mObservers.size(); i++) {SingleFileObserver sfo = (SingleFileObserver) mObservers.get(i);sfo.startWatching();}};@Overridepublic void stopWatching() {if (mObservers == null)return;for (int i = 0; i < mObservers.size(); i++) {SingleFileObserver sfo = (SingleFileObserver) mObservers.get(i);sfo.stopWatching();}mObservers.clear();mObservers = null;};@Overridepublic void onEvent(int event, String path) {switch (event) {case FileObserver.ACCESS:Log.i("RecursiveFileObserver", "ACCESS: " + path);break;case FileObserver.ATTRIB:Log.i("RecursiveFileObserver", "ATTRIB: " + path);break;case FileObserver.CLOSE_NOWRITE:Log.i("RecursiveFileObserver", "CLOSE_NOWRITE: " + path);break;case FileObserver.CLOSE_WRITE:Log.i("RecursiveFileObserver", "CLOSE_WRITE: " + path);break;case FileObserver.CREATE: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;case FileObserver.OPEN:Log.i("RecursiveFileObserver", "OPEN: " + path);break;default:Log.i("RecursiveFileObserver", "DEFAULT(" + event + " : " + path);break;}}/** * Monitor single directory and dispatch all events to its parent, with full * path. */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;}@Overridepublic void onEvent(int event, String path) {String newPath = mPath + "/" + path;RecursiveFileObserver.this.onEvent(event, newPath);}}}