昨天因为项目需要,需要做一个damo,用到了文件监听的功能,所以就使用了FileObserver(文件观察器)这个类,结果就被坑的不行不行的,昨天下班已经身心俱疲,本着跟bug呲牙必报的精神,这里要将这笔账记下,也希望大家以后不会在这上面浪费时间。

FileObserver的功能

故名思议,就是监听文件的事件啦,根据官方给出的文档,有以下几种事件的响应,对应不同的事件常量。

常量名

对应事件

ACCESS

打开文件后读取文件的操作

ALL_EVENTS

事件列表中的所有事件

ATTRIB

未明操作

CLOSE_NOWRITE

只读文件被关闭

CLOSE_WRITE

读写文件被编辑并关闭

CREATE

文件被创建创建

DELETE

文件被删除

DELETE_SELF

自删除事件

MODIFY

文件被修改

MOVED_FROM

移出事件

MOVED_TO

移入事件

MOVE_SELF

自移动事件

OPEN

文件被打开

这些常量都是在FileObserver类里面的,因此可以通过FileObserver.XXX来调用。

FileObserver可以监听两种类型的文件:一种是单个文件,另一种是文件目录。需要注意的是监听文件目录的时候有个不能递归子目录的问题,因此要么确保监听的文件下没有子目录,要么做特殊的操作,手动递归监听每一个子目录。

FileObserver的用法

1.FileObserver是一个抽象类,使用的时候我们需要自己实现一个类来继承FileObserver。

2.编写构造方法

构造方法有两种写法:

第一种是只传路径参数

public FileObserver (String path)

其实使用这种方法的时候,为了防止发生嵌套调用产生死循环,我们可以在实现方法的时候进行一点优化。

public FileObserver (String path) {
super( path, FileObserver.CREATE | FileObserver.DELETE );
}

可以看到,我们继承super方法的时候,调用了父类的另外一种构造参数,在第二个参数中,将我们需要监听的事件传了进去,这样就可以保证过滤掉不需要的事件,降低发生死循环的概率。

第二种传路径和需要监听的事件

public FileObserver (String path, int mask)

在第一种方法的优化中我们已经看到了这种方法的用法,使用中也可以使用这种方法来进行构造,相对于第一种方法,这种方法耦合性更低一些。

3.实现onEvent(int event, String path)方法

前面说了,FileObserver是一个抽象类,这个onEvent方法就是它的抽象方法,需要在子类中进行实现。

@Override
public void onEvent(int event, String path) {
/*event的值是与0x40000000进行或运算后的值,所以在case之前需要先和FileObserver.ALL_EVENTS进行与运算*/
int e = event & FileObserver.ALL_EVENTS;
switch (e) {
case FileObserver.CREATE:
/*do something*/
break;
}
}

4.开启与关闭监听

在FileObserver中提供了开启和关闭监听的方法,只需要直接调用就可以了。

startWatching(); //开启监听

stopWatching(); //结束监听

需要注意的一点是作为监听者的FileObserver需要一直保持一个引用来防止被java的GC机制干掉,所以最好和一个持久性引用绑定工作,一般我们都使用Service来进行绑定使用。

5.权限问题

网上所有关于使用FileObserver的教程都没提及权限的申请,但我昨天使用中就是因为权限的问题导致一直监听不到。而且FileObserver用到的权限没申请的时候不是常规的报错提示,只是默默地罢工了,个人认为是在是最大的坑。

在清单文件中加入以下权限:

建议是在遇到如何都监听不到的时候再加权限,毕竟权限申请太多有的用户很反感的。

总结

通过上面的介绍可以看到,FileObserver的坑真的是超多,真是滩险石多,需要耐心和谨慎来尽量避免。

引用声明