android.os下的FileObserver类是一个用于监听文件访问、创建、修改、删除、移动等操作的监听器,基于linux的inotify。 FileObserver 是个抽象类,必须继承它才能使用。每个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,包括上面的所有事件 这些都是FileObserver的静态共有属性。 下面举个例子说明一下其用法。 比如,我要监听sd卡的目录创建事件,新建一个类SDCardListener继承FileObserver:
scala 代码解读复制代码import android.os.FileObserver;
import android.util.Log;
/**
* sd卡上的目录创建监听器
* @author chroya
*
*/
public class SDCardListener extends FileObserver {
public SDCardListener(String path) {
/*
* 这种构造方法是默认监听所有事件的,如果使用super(String,int)这种构造方法,
* 则int参数是要监听的事件类型.
*/
super(path);
}
@Override
public void onEvent(int event, String path) {
switch(event) {
case FileObserver.ALL_EVENTS:
Log.d("all", "path:"+ path);
break;
case FileObserver.CREATE:
Log.d("Create", "path:"+ path);
break;
}
}
}
onEvent是回调,系统监听到事件后会触发此事件,参数event就是上面所说的事件类型,根据类型,我们可以做相应的处理,参数path就是触发事件的目录。
然后使用它:
scss 代码解读复制代码SDCardListener listener = new SDCardListener("/sdcard");
//开始监听
listener.startWatching();
/*
* 在这里做一些操作,比如创建目录什么的
*/
//最后停止监听
listener.stopWatching();
如果要在onEvent中做较多操作,最好用线程去做 ,以免因为阻塞接收不到后面的事件。 最后补充一点,比较重要 : FileObserver对象必须保持一个引用,确保不被垃圾收集器回收掉,否则就不会触发事件了。
让我们实现 FileObserver + 前台服务 的结合,确保在后台持续监听,即使应用被杀掉也能保持运行!下面分成几部分来讲解:
🚦一、前台服务基本结构
在 Android 中,前台服务需要:
- 创建
Service
来管理FileObserver
。 - 创建通知,确保服务在前台运行,避免系统回收。
- 启动服务时,绑定
FileObserver
。
🏗️二、创建前台服务
1. FileMonitorService.java
java 代码解读复制代码java复制编辑import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Intent;
import android.os.Build;
import android.os.FileObserver;
import android.os.IBinder;
import android.util.Log;
public class FileMonitorService extends Service {
private static final String TAG = "FileMonitorService";
private static final String CHANNEL_ID = "FileMonitorChannel";
private SDCardListener fileObserver;
private String directoryPath = "/sdcard"; // 替换为你要监听的目录
@Override
public void onCreate() {
super.onCreate();
createNotificationChannel();
startForeground(1, createNotification());
startFileObserver();
Log.d(TAG, "Service started and observer initialized.");
}
private void startFileObserver() {
fileObserver = new SDCardListener(directoryPath);
fileObserver.startWatching();
Log.d(TAG, "Started watching: " + directoryPath);
}
private void stopFileObserver() {
if (fileObserver != null) {
fileObserver.stopWatching();
Log.d(TAG, "Stopped watching: " + directoryPath);
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY; // 确保服务在被系统杀掉时重启
}
@Override
public void onDestroy() {
super.onDestroy();
stopFileObserver();
Log.d(TAG, "Service destroyed and observer stopped.");
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(
CHANNEL_ID, "File Monitor Service", NotificationManager.IMPORTANCE_LOW);
NotificationManager manager = getSystemService(NotificationManager.class);
if (manager != null) {
manager.createNotificationChannel(channel);
}
}
}
private Notification createNotification() {
Notification.Builder builder = new Notification.Builder(this)
.setContentTitle("File Monitoring Active")
.setContentText("Watching directory: " + directoryPath)
.setSmallIcon(android.R.drawable.ic_menu_info_details);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
builder.setChannelId(CHANNEL_ID);
}
return builder.build();
}
}
2. SDCardListener.java
java 代码解读复制代码java复制编辑import android.os.FileObserver;
import android.util.Log;
public class SDCardListener extends FileObserver {
private static final String TAG = "SDCardListener";
public SDCardListener(String path) {
super(path, FileObserver.ALL_EVENTS);
}
@Override
public void onEvent(int event, String path) {
switch (event) {
case FileObserver.CREATE:
Log.d(TAG, "File created: " + path);
break;
case FileObserver.DELETE:
Log.d(TAG, "File deleted: " + path);
break;
case FileObserver.MODIFY:
Log.d(TAG, "File modified: " + path);
break;
case FileObserver.MOVED_FROM:
Log.d(TAG, "File moved from: " + path);
break;
case FileObserver.MOVED_TO:
Log.d(TAG, "File moved to: " + path);
break;
default:
Log.d(TAG, "Event " + event + " on: " + path);
break;
}
}
}
3. AndroidManifest.xml 中声明服务和权限
ini 代码解读复制代码xml复制编辑name ="android.permission.FOREGROUND_SERVICE" />
name ="android.permission.WRITE_EXTERNAL_STORAGE" />
name ="android.permission.READ_EXTERNAL_STORAGE" />
android:name=".FileMonitorService"
android:foregroundServiceType="dataSync" />
4. 启动/停止服务
你可以在 MainActivity
里启动/停止前台服务:
scala 代码解读复制代码java复制编辑import android.content.Intent;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 启动服务
Intent intent = new Intent(this, FileMonitorService.class);
startForegroundService(intent);
}
@Override
protected void onDestroy() {
super.onDestroy();
// 停止服务
Intent intent = new Intent(this, FileMonitorService.class);
stopService(intent);
}
}
🎯五、运行效果
- 启动 App 后,通知栏显示“File Monitoring Active”,服务进入前台。
- 任何对
/sdcard
目录的操作(如文件创建、删除、修改、移动等),都会触发SDCardListener
,输出日志。 - App 被杀掉后,服务依然存活,持续监听。即使系统回收,也会自动重启(
START_STICKY
)。
⚡六、优化建议
- 递归监听子目录:
FileObserver
不能自动递归监听所有子目录。如果需要递归监听,创建多个FileObserver
对象,每个对象监听一个子目录。 - 电量优化:
FileObserver
是 native 的inotify
实现,功耗较低,但频繁操作大目录时,建议加上事件合并、去抖动逻辑。 - 异常处理:
防止监听路径被删除、SD 卡拔出、权限丢失等意外情况引起的崩溃。
评论记录:
回复评论: