android监听文件和目录的创建删除移动等事件

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复制编辑<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

<application>
    <service
        android:name=".FileMonitorService"
        android:foregroundServiceType="dataSync" />
</application>

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);
    }
}

🎯五、运行效果

  1. 启动 App 后,通知栏显示"File Monitoring Active",服务进入前台。
  2. 任何对 /sdcard 目录的操作(如文件创建、删除、修改、移动等),都会触发 SDCardListener,输出日志。
  3. App 被杀掉后,服务依然存活,持续监听。即使系统回收,也会自动重启(START_STICKY)。

⚡六、优化建议

  • 递归监听子目录:
    FileObserver 不能自动递归监听所有子目录。如果需要递归监听,创建多个 FileObserver 对象,每个对象监听一个子目录。
  • 电量优化:
    FileObserver 是 native 的 inotify 实现,功耗较低,但频繁操作大目录时,建议加上事件合并、去抖动逻辑。
  • 异常处理:
    防止监听路径被删除、SD 卡拔出、权限丢失等意外情况引起的崩溃。
相关推荐
Devil枫41 分钟前
Kotlin高级特性深度解析
android·开发语言·kotlin
ChinaDragonDreamer43 分钟前
Kotlin:2.1.20 的新特性
android·开发语言·kotlin
雨白11 小时前
Jetpack系列(二):Lifecycle与LiveData结合,打造响应式UI
android·android jetpack
kk爱闹13 小时前
【挑战14天学完python和pytorch】- day01
android·pytorch·python
每次的天空14 小时前
Android-自定义View的实战学习总结
android·学习·kotlin·音视频
恋猫de小郭15 小时前
Flutter Widget Preview 功能已合并到 master,提前在体验毛坯的预览支持
android·flutter·ios
断剑重铸之日16 小时前
Android自定义相机开发(类似OCR扫描相机)
android
随心最为安16 小时前
Android Library Maven 发布完整流程指南
android
岁月玲珑16 小时前
【使用Android Studio调试手机app时候手机老掉线问题】
android·ide·android studio
还鮟20 小时前
CTF Web的数组巧用
android