You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android如何监听特定文件夹的文件增删(支持后台/进程被杀)

解决方案:持续监听WhatsApp状态文件夹的文件变化

针对你遇到的应用后台/被杀后无法感知WhatsApp状态文件更新的问题,以下是分层实现的方案:

1. 基础实时监听:ContentObserver + 媒体库过滤

WhatsApp的状态文件会被系统媒体库扫描,通过注册ContentObserver监听媒体库的图片/视频更新,过滤目标文件夹路径即可感知变化,无需常驻后台:

class StatusMediaObserver(
    private val resolver: ContentResolver,
    private val updateCallback: () -> Unit
) : ContentObserver(Handler(Looper.getMainLooper())) {

    override fun onChange(selfChange: Boolean, uri: Uri?) {
        super.onChange(selfChange, uri)
        // 仅过滤WhatsApp状态文件夹的文件
        val selection = "${MediaStore.MediaColumns.DATA} LIKE ?"
        val args = arrayOf("%/WhatsApp/Media/.Statuses/%")
        resolver.query(
            uri ?: Images.Media.EXTERNAL_CONTENT_URI,
            null, selection, args, null
        )?.use { cursor ->
            if (cursor.moveToFirst()) updateCallback()
        }
    }
}

// 注册监听(在Activity/Fragment的onCreate中调用)
val observer = StatusMediaObserver(contentResolver) {
    // 触发状态列表刷新逻辑
    loadLatestStatuses()
}
contentResolver.registerContentObserver(Images.Media.EXTERNAL_CONTENT_URI, true, observer)
contentResolver.registerContentObserver(Videos.Media.EXTERNAL_CONTENT_URI, true, observer)
  • 注意:Android 10+需申请ACCESS_MEDIA_LOCATION权限,同时要处理媒体库扫描的延迟问题。

2. 后台常驻监听:前台服务 + FileObserver

如果需要更实时的文件变化感知,可结合前台服务提升进程优先级,配合FileObserver直接监听目标文件夹:

class StatusMonitorService : Service() {
    private lateinit var folderObserver: FileObserver

    override fun onCreate() {
        super.onCreate()
        // 启动前台通知(Android 8+强制要求)
        val notification = NotificationCompat.Builder(this, "STATUS_MONITOR_CHANNEL")
            .setContentTitle("状态监听中")
            .setSmallIcon(R.drawable.ic_notification)
            .build()
        startForeground(1001, notification)

        // 初始化文件夹监听
        val statusDir = File(
            "${getExternalFilesDir(null)?.parent}/com.whatsapp/WhatsApp/Media/.Statuses/"
        )
        folderObserver = object : FileObserver(statusDir.path, FileObserver.CREATE or FileObserver.DELETE) {
            override fun onEvent(event: Int, path: String?) {
                path ?: return
                when(event) {
                    FileObserver.CREATE -> handleNewStatus(File(statusDir, path))
                    FileObserver.DELETE -> handleDeletedStatus(path)
                }
                // 发送广播通知UI更新
                sendBroadcast(Intent("STATUS_UPDATED_ACTION"))
            }
        }
        folderObserver.startWatching()
    }

    private fun handleNewStatus(file: File) {
        // 将状态文件复制到应用私有目录保存
        val destFile = File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), file.name)
        file.copyTo(destFile, overwrite = true)
    }

    private fun handleDeletedStatus(fileName: String) {
        // 同步删除本地已保存的对应文件
        val localFile = File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), fileName)
        if (localFile.exists()) localFile.delete()
    }

    override fun onDestroy() {
        super.onDestroy()
        folderObserver.stopWatching()
    }

    override fun onBind(intent: Intent): IBinder? = null
}
  • 注意:Android 12+需申请POST_NOTIFICATIONS权限,且前台服务的使用需符合Google Play的政策要求。

3. 进程被杀后的兜底方案

极端情况下进程被系统回收,需补充以下机制恢复监听:

  • 开机自启动:注册BOOT_COMPLETED广播接收器,开机后自动启动监听服务(Android 10+需用户手动开启应用自启动权限)
  • WorkManager定期扫描:使用PeriodicWorkRequest每隔15分钟扫描一次状态文件夹,同步最新文件,作为实时监听的兜底:
// 启动定期扫描任务
val scanWork = PeriodicWorkRequestBuilder<StatusScanWorker>(15, TimeUnit.MINUTES)
    .build()
WorkManager.getInstance(context).enqueue(scanWork)

// Worker实现
class StatusScanWorker(context: Context, params: WorkerParameters) : Worker(context, params) {
    override fun doWork(): Result {
        val statusDir = File(
            "${getExternalFilesDir(null)?.parent}/com.whatsapp/WhatsApp/Media/.Statuses/"
        )
        if (statusDir.exists()) {
            val remoteFiles = statusDir.listFiles()?.map { it.name } ?: emptyList()
            val localFiles = getExternalFilesDir(Environment.DIRECTORY_PICTURES)?.listFiles()?.map { it.name } ?: emptyList()
            
            // 同步新增文件
            remoteFiles.filter { it !in localFiles }.forEach { fileName ->
                File(statusDir, fileName).copyTo(File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), fileName), overwrite = true)
            }
        }
        return Result.success()
    }
}

4. 权限适配要点

  • Android 10+:优先使用媒体库API,若需直接访问文件夹,可引导用户通过ACTION_OPEN_DOCUMENT_TREE选择.Statuses文件夹,使用DocumentFile进行操作(避免MANAGE_EXTERNAL_STORAGE权限的审核风险)
  • Android 13+:需申请READ_MEDIA_IMAGES和READ_MEDIA_VIDEO权限,替代旧的READ_EXTERNAL_STORAGE

内容的提问来源于stack exchange,提问作者Danish

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 16:23:14