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 卡拔出、权限丢失等意外情况引起的崩溃。
相关推荐
鸿蒙布道师1 小时前
鸿蒙NEXT开发动画案例2
android·ios·华为·harmonyos·鸿蒙系统·arkui·huawei
androidwork1 小时前
Kotlin Android工程Mock数据方法总结
android·开发语言·kotlin
xiangxiongfly9153 小时前
Android setContentView()源码分析
android·setcontentview
人间有清欢5 小时前
Android开发补充内容
android·okhttp·rxjava·retrofit·hilt·jetpack compose
人间有清欢5 小时前
Android开发报错解决
android
每次的天空7 小时前
Android学习总结之kotlin协程面试篇
android·学习·kotlin
每次的天空9 小时前
Android学习总结之Binder篇
android·学习·binder
峥嵘life9 小时前
Android 有线网开发调试总结
android
是店小二呀10 小时前
【算法-链表】链表操作技巧:常见算法
android·c++·算法·链表
zhifanxu11 小时前
Kotlin 遍历
android·开发语言·kotlin