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
相关产品推荐
相关产品推荐

