android -- FileObserver 类用法及限制


    

android -- FileObserver 类用法及限制

分类: Android应用编写学习 2420人阅读 评论(1) 收藏 举报
最近有个需求需要监控目录下的文件及目录情况,查了一下android上面正在有个类:FileObserver,下面简要说明一下用法及限制。


android.os.FileObserver
Monitors files (using inotify) to fire an event after files are accessed or changed by 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.


FileObserver类是一个用于监听文件访问、创建、修改、删除、移动等操作的监听器,基于linux的inotify。 
FileObserver 是个抽象类,必须继承它才能使用。每个FileObserver对象监听一个单独的文件或者文件夹,如果监视的是一个文件夹,
那么文件夹下所有的文件和级联子目录的改变都会触发监听的事件。


其实不然,经过测试并不支持递归,对于监听目录的子目录中的文件改动,FileObserver 对象是无法收到事件回调的,不仅这样,
监听目录的子目录本身的变动也收不到事件回调。原因是由 linux 的 inotify 机制本身决定的,基于 inotify 实现的 FileObserver 自然也不支持递归监听。


1、概述用法


FileObserver 是个抽象类,必须继承它才能使用


可以监听的事件类型:
ACCESS : 即文件被访问
MODIFY : 文件被修改
ATTRIB : 文件属性被修改,如 chmod、chown、touch 等
CLOSE_WRITE : 可写文件被 close
CLOSE_NOWRITE : 不可写文件被 close
OPEN : 文件被 open
MOVED_FROM : 文件被移走,如 mv
MOVED_TO : 文件被移来,如 mv、cp
CREATE : 创建新文件
DELETE : 文件被删除,如 rm
DELETE_SELF : 自删除,即一个可执行文件在执行时删除自己
MOVE_SELF : 自移动,即一个可执行文件在执行时移动自己
CLOSE : 文件被关闭,等同于(IN_CLOSE_WRITE | IN_CLOSE_NOWRITE)
ALL_EVENTS : 包括上面的所有事件
可以SDK DEVELOP上有更详细的介绍


1、创建目录监听器

  1. <span style="font-size: 14px;">class MyFileObserver extends FileObserver {  
  2.         // 这种构造方法是默认监听所有事件的,如果使用super(String,int)这种构造方法,则int参数是要监听的事件类型。  
  3.         // 为了防止嵌套消息调用,建议使用 super(String,int) 按需创建监控消息值  
  4.         public MyFileObserver(String path) {  
  5.             super(path, FileObserver.CLOSE_WRITE | FileObserver.CREATE | FileObserver.DELETE  
  6.                     | FileObserver.DELETE_SELF );  
  7.             //super(path,FileObserver.ALL_EVENTS);  
  8.         }  
  9.   
  10.         @Override  
  11.         public void onEvent(int event, String path) {  
  12.             synchronized (mutex) {  
  13.                 // 这里注意 event 值是与 0x40000000或上后的值,所以需要case时需要先进行 &FileObserver.ALL_EVENTS  
  14.                 int el = event & FileObserver.ALL_EVENTS;  
  15.                 Log.i(TAG, "onEvent event:" + el + " path:" + path);  
  16.                 switch(el){  
  17.                     //TODO 这里case所有的监听的事件类型 FileObserver.xx 静态属性  
  18.                     //如果要在onEvent中做较多操作,最好使用线程去做 ,以免因为阻塞接收不到后面的事件。  
  19.                       
  20.                     //try {  
  21.                     //  handler.obtainMessage(el, path).sendToTarget();  
  22.                     //} catch (Exception e) {  
  23.                     //  Log.e(TAG, "Monitor FileObserver.onEvent error:" + e);  
  24.                     //}  
  25.                 }  
  26.                 }  
  27.             }  
  28.         }  
  29.     };</span>  
<span style="font-size: 14px;">class MyFileObserver extends FileObserver {
		// 这种构造方法是默认监听所有事件的,如果使用super(String,int)这种构造方法,则int参数是要监听的事件类型。
		// 为了防止嵌套消息调用,建议使用 super(String,int) 按需创建监控消息值
		public MyFileObserver(String path) {
			super(path, FileObserver.CLOSE_WRITE | FileObserver.CREATE | FileObserver.DELETE
					| FileObserver.DELETE_SELF );
			//super(path,FileObserver.ALL_EVENTS);
		}

		@Override
		public void onEvent(int event, String path) {
			synchronized (mutex) {
				// 这里注意 event 值是与 0x40000000或上后的值,所以需要case时需要先进行 &FileObserver.ALL_EVENTS
				int el = event & FileObserver.ALL_EVENTS;
				Log.i(TAG, "onEvent event:" + el + " path:" + path);
				switch(el){
					//TODO 这里case所有的监听的事件类型 FileObserver.xx 静态属性
					//如果要在onEvent中做较多操作,最好使用线程去做 ,以免因为阻塞接收不到后面的事件。
					
					//try {
					//	handler.obtainMessage(el, path).sendToTarget();
					//} catch (Exception e) {
					//	Log.e(TAG, "Monitor FileObserver.onEvent error:" + e);
					//}
				}
				}
			}
		}
	};</span>

使用线程处理:
private Handler handler = null;
private HandlerThread th = null;


th = new HandlerThread("sectionStorage");
th.start();
handler = new Handler(th.getLooper(), callback);


fobs = new MyFileObserver(root);


消息处理:

  1. <span style="font-size: 14px;">Handler.Callback callback = new Handler.Callback() {  
  2.         @Override  
  3.         public boolean handleMessage(Message msg) {  
  4.             Log.i(TAG, "callback msg.what=" + msg.what + " msg.obj:" + msg.obj);  
  5.             synchronized (mutex) {  
  6.                 try {  
  7.                         switch (msg.what) {  
  8.                         case FileObserver.CLOSE_WRITE:  
  9.                             onFileWriteClosed((String) msg.obj);  
  10.                             break;  
  11.                         case FileObserver.CREATE:  
  12.                             onFileCreate((String) msg.obj);  
  13.                             break;  
  14.                         case FileObserver.DELETE:  
  15.                             onFileDeleted((String) msg.obj);  
  16.                             break;  
  17.                         case FileObserver.DELETE_SELF:  
  18.                             onRootDeleted();  
  19.                             break;  
  20.                         }  
  21.                     } catch (Throwable e) {  
  22.                         Log.e(TAG, "handleMessage error:" + e);  
  23.                     }         
  24.             }  
  25.         }  
  26. };</span>  
<span style="font-size: 14px;">Handler.Callback callback = new Handler.Callback() {
		@Override
		public 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);
					}		
			}
		}
};</span>

2、给目录设置监听器


MyFileObserver listener = new MyFileObserver("目录");
//开始监听     
listener.startWatching(); 
    
/*   
* 在这里做一些操作,比如创建目录什么的   
*/    
 
//停止监听  
listener.stopWatching(); 


2、对于递归监听的实现代码,可参考这里:


https://code.google.com/p/collimator/source/browse/trunk/src/com/toraleap/collimator/util/RecursiveFileObserver.java?spec=svn22&r=22


摘抄如下:
为了监听整个文件系统的变化,必须得实现这个递归监听,怎么办呢?先查查大家是怎么用 inotify 实现递归监听的,
搜索结果说明了一切,对每个子目录递归的调用 inotify,也就是说在 Android 中,也得通过遍历目录树,建立一系列 
FileObserver 对象来实现这个功能
,很笨吧。本来很担心这样做对系统的效率影响极大,但是大家都是这么实现的,
我也本着实践出真知的原则,写下了如下的 RecursiveFileObserver 类:


====================================================================================================================


不过拿下来后编译发现一点问题,我的代码如下:(修改了一下编译错误而已,代码抄自上面)


  1. <span style="font-size: 14px;">package com.test.fileobserver;  
  2.   
  3. import java.io.File;  
  4. import java.util.ArrayList;  
  5. import java.util.List;  
  6. import java.util.Stack;  
  7.   
  8. import android.os.FileObserver;  
  9. import android.util.Log;  
  10.   
  11. @SuppressWarnings(value = { "rawtypes""unchecked" })  
  12. public class RecursiveFileObserver extends FileObserver {  
  13.   
  14.     /** Only modification events */  
  15.     public static int CHANGES_ONLY = CREATE | DELETE | CLOSE_WRITE  
  16.             | DELETE_SELF | MOVE_SELF | MOVED_FROM | MOVED_TO;  
  17.   
  18.     List mObservers;  
  19.     String mPath;  
  20.     int mMask;  
  21.   
  22.     public RecursiveFileObserver(String path) {  
  23.         this(path, ALL_EVENTS);  
  24.     }  
  25.   
  26.     public RecursiveFileObserver(String path, int mask) {  
  27.         super(path, mask);  
  28.         mPath = path;  
  29.         mMask = mask;  
  30.     }  
  31.   
  32.     @Override  
  33.     public void startWatching() {  
  34.         if (mObservers != null)  
  35.             return;  
  36.   
  37.         mObservers = new ArrayList();  
  38.         Stack stack = new Stack();  
  39.         stack.push(mPath);  
  40.   
  41.         while (!stack.isEmpty()) {  
  42.             String parent = (String)stack.pop();  
  43.             mObservers.add(new SingleFileObserver(parent, mMask));  
  44.             File path = new File(parent);  
  45.             File[] files = path.listFiles();  
  46.             if (null == files)  
  47.                 continue;  
  48.             for (File f : files) {  
  49.                 if (f.isDirectory() && !f.getName().equals(".")  
  50.                         && !f.getName().equals("..")) {  
  51.                     stack.push(f.getPath());  
  52.                 }  
  53.             }  
  54.         }  
  55.   
  56.         for (int i = 0; i < mObservers.size(); i++) {  
  57.             SingleFileObserver sfo = (SingleFileObserver) mObservers.get(i);  
  58.             sfo.startWatching();  
  59.         }  
  60.     };  
  61.   
  62.     @Override  
  63.     public void stopWatching() {  
  64.         if (mObservers == null)  
  65.             return;  
  66.   
  67.         for (int i = 0; i < mObservers.size(); i++) {  
  68.             SingleFileObserver sfo = (SingleFileObserver) mObservers.get(i);  
  69.             sfo.stopWatching();  
  70.         }  
  71.           
  72.         mObservers.clear();  
  73.         mObservers = null;  
  74.     };  
  75.   
  76.     @Override  
  77.     public void onEvent(int event, String path) {  
  78.         switch (event) {  
  79.         case FileObserver.ACCESS:  
  80.             Log.i("RecursiveFileObserver""ACCESS: " + path);  
  81.             break;  
  82.         case FileObserver.ATTRIB:  
  83.             Log.i("RecursiveFileObserver""ATTRIB: " + path);  
  84.             break;  
  85.         case FileObserver.CLOSE_NOWRITE:  
  86.             Log.i("RecursiveFileObserver""CLOSE_NOWRITE: " + path);  
  87.             break;  
  88.         case FileObserver.CLOSE_WRITE:  
  89.             Log.i("RecursiveFileObserver""CLOSE_WRITE: " + path);  
  90.             break;  
  91.         case FileObserver.CREATE:  
  92.             Log.i("RecursiveFileObserver""CREATE: " + path);  
  93.             break;  
  94.         case FileObserver.DELETE:  
  95.             Log.i("RecursiveFileObserver""DELETE: " + path);  
  96.             break;  
  97.         case FileObserver.DELETE_SELF:  
  98.             Log.i("RecursiveFileObserver""DELETE_SELF: " + path);  
  99.             break;  
  100.         case FileObserver.MODIFY:  
  101.             Log.i("RecursiveFileObserver""MODIFY: " + path);  
  102.             break;  
  103.         case FileObserver.MOVE_SELF:  
  104.             Log.i("RecursiveFileObserver""MOVE_SELF: " + path);  
  105.             break;  
  106.         case FileObserver.MOVED_FROM:  
  107.             Log.i("RecursiveFileObserver""MOVED_FROM: " + path);  
  108.             break;  
  109.         case FileObserver.MOVED_TO:  
  110.             Log.i("RecursiveFileObserver""MOVED_TO: " + path);  
  111.             break;  
  112.         case FileObserver.OPEN:  
  113.             Log.i("RecursiveFileObserver""OPEN: " + path);  
  114.             break;  
  115.         default:  
  116.             Log.i("RecursiveFileObserver""DEFAULT(" + event + " : " + path);  
  117.             break;  
  118.         }  
  119.     }  
  120.   
  121.     /** 
  122.      * Monitor single directory and dispatch all events to its parent, with full 
  123.      * path. 
  124.      */  
  125.     class SingleFileObserver extends FileObserver {  
  126.         String mPath;  
  127.   
  128.         public SingleFileObserver(String path) {  
  129.             this(path, ALL_EVENTS);  
  130.             mPath = path;  
  131.         }  
  132.   
  133.         public SingleFileObserver(String path, int mask) {  
  134.             super(path, mask);  
  135.             mPath = path;  
  136.         }  
  137.   
  138.         @Override  
  139.         public void onEvent(int event, String path) {  
  140.             String newPath = mPath + "/" + path;  
  141.             RecursiveFileObserver.this.onEvent(event, newPath);  
  142.         }  
  143.     }  
  144. }  
  145. </span>  
<span style="font-size: 14px;">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;
	}

	@Override
	public 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();
		}
	};

	@Override
	public 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;
	};

	@Override
	public 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;
		}

		@Override
		public void onEvent(int event, String path) {
			String newPath = mPath + "/" + path;
			RecursiveFileObserver.this.onEvent(event, newPath);
		}
	}
}
</span>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
React Native的 `react-native-android-keyboard-adjust` 库可以用来调整安卓键盘的行为。在0.63版本中,使用方法如下: 1. 安装库 使用以下命令安装库: ``` npm install react-native-android-keyboard-adjust ``` 2. 链接原生代码 使用以下命令来链接原生代码: ``` npx react-native link react-native-android-keyboard-adjust ``` 或者手动链接,按照以下步骤: (1) 在 `android/settings.gradle` 文件中添加以下代码: ``` include ':react-native-android-keyboard-adjust' project(':react-native-android-keyboard-adjust').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-android-keyboard-adjust/android') ``` (2) 在 `android/app/build.gradle` 文件中添加以下代码: ``` dependencies { // ... implementation project(':react-native-android-keyboard-adjust') } ``` (3) 在 `MainApplication.java` 文件中导入以下代码: ``` import com.reactnativeandroidkeyboardadjust.ReactNativeAndroidKeyboardAdjustPackage; ``` (4) 在 `MainApplication.java` 文件的 `getPackages()` 方法中添加以下代码: ``` new ReactNativeAndroidKeyboardAdjustPackage() ``` 3. 使用 在需要调整键盘行为的组件上,添加 `androidKeyboardAdjust` 属性,值可以为以下三种: - `none`: 不调整键盘行为 - `pan`: 键盘出现时,组件会向上滚动,以避免被键盘遮挡 - `resize`: 键盘出现时,组件会自动调整大小,以避免被键盘遮挡 例如: ```jsx <TextInput androidKeyboardAdjust="pan" // ... /> ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值