Чтобы отследить события модификации файла (-ов), существует класс FileObserver, который умеет мониторить объекты файловой системы в отдельном потоке.
Также, для пущей важности можно создать отдельный сервис и запихнуть этот механизм туда.
Создание
1) создать сервис, внутри которого создать экземпляр класса FileObserver и запустить:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
public class FileObserverService extends Service { public static final String EXTRA_FILE_PATH = "EXTRA_FILE_PATH"; private static FileObserver fileObserver; @Override public int onStartCommand(Intent intent, int flags, int startId) { if ((intent.hasExtra(EXTRA_FILE_PATH))) { fileObserver = new FileObserver(intent.getStringExtra(EXTRA_FILE_PATH)) { @Override public void onEvent(int event, String path) { ... Log.d("FILEOBSERVER_EVENT", "Event with id " + Integer.toHexString(event) + " happened"); switch (event) { case FileObserver.MODIFY: ... break; } } }; fileObserver.startWatching(); } return Service.START_NOT_STICKY; } @Override public void onCreate() { super.onCreate(); } @Override public IBinder onBind(Intent intent) { return null; } } |
2) Объявить сервис в манифесте:
1 2 3 4 5 6 7 8 9 10 |
<manifest > <application > <service android:name=".FileObserverService" android:enabled="true" android:exported="true" > </service> ... </application > </manifest > |
3) создать намерение и запустить сервис:
1 2 3 |
Intent intent = new Intent(this, FileObserverService.class); intent.putExtra(FileObserverService.EXTRA_FILE_PATH, "/path/to/file"); this.startService(intent); |
Отправка сообщений в активность
Чтобы из сервиса отправить уведомление в активность о модификации файла:
1) Создать BroadcastReceiver в своей активности, который получит Intent с переданным сообщением.
1 2 3 4 5 6 7 8 9 10 11 |
private BroadcastReceiver bReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(FileObserverService.ACTION_OBSERVER_EVENT_COME)) { // обрабатываем сигнал об изменении файла int eventMode = intent.getIntExtra(FileObserverService.EXTRA_EVENT_MODE, 0); ... } } }; LocalBroadcastManager bManager; |
2) создать IntentFilter и зарегистрировать BroadcastReceiver в onCreate():
1 2 3 4 |
bManager = LocalBroadcastManager.getInstance(this); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(FileObserverService.ACTION_OBSERVER_EVENT_COME); bManager.registerReceiver(bReceiver, intentFilter); |
3) отменить регистрацию BroadcastReceiver в onDestroy():
1 |
bManager.unregisterReceiver(bReceiver); |
4) отправить сообщение из сервиса при наступлении события модификации файла:
1 2 3 4 5 6 7 8 9 |
public static final String ACTION_OBSERVER_EVENT_COME = "com.your.package.ACTION_OBSERVER_EVENT_COME"; public static final String EXTRA_EVENT_MODE = "EXTRA_EVENT_MODE"; public void onEvent(int event, String path) { Intent intent = new Intent(ACTION_OBSERVER_EVENT_COME); intent.putIntExtra(EXTRA_EVENT_MODE, event); LocalBroadcastManager.getInstance(this).sendBroadcast(intent); ... } |
Проблема
Через какое-то время отслеживание файла перестает работать (обработчик onEvent() не вызывается).
Обсуждение на stackoverflow.
Причина:
Описание к FileObserver:
“Warning: If a FileObserver is garbage collected, it will stop sending events. To ensure you keep receiving events, you must keep a reference to the FileObserver instance from some other live object.”
Решение:
1) Созданный экземпляр класса FileObserver сохранять как свойство класса, чтобы сборщик мусора его не удалял. Мне не помогло.
2) Как и в (1), экземпляр сохранять как свойство класса, но также пометить как static. Мне помогло.
1 |
private static FIleObserver mFileObserver; |