Подтвердить что ты не робот

Как вы реализуете FileObserver из службы Android

Как вы структурируете приложение для Android, чтобы запустить Service, чтобы использовать FileObserver, чтобы при изменении наблюдаемого каталога (т.е. пользователь делает снимок) выполняется другой код. При отладке метод onEvent никогда не запускается.

Вот событие onStart, которое у меня есть в моей службе. Toast запускается для "My Service Started..."

public final String TAG = "DEBUG";
public static FileObserver observer;    

@Override
public void onStart(Intent intent, int startid) {       
        Log.d(TAG, "onStart");

        final String pathToWatch = android.os.Environment.getExternalStorageDirectory().toString() + "/DCIM/Camera/";       
        Toast.makeText(this, "My Service Started and trying to watch " + pathToWatch, Toast.LENGTH_LONG).show();

        observer = new FileObserver(pathToWatch) { // set up a file observer to watch this directory on sd card
            @Override
            public void onEvent(int event, String file) {
                //if(event == FileObserver.CREATE && !file.equals(".probe")){ // check if its a "create" and not equal to .probe because thats created every time camera is launched
                    Log.d(TAG, "File created [" + pathToWatch + file + "]");

                    Toast.makeText(getBaseContext(), file + " was saved!", Toast.LENGTH_LONG);                  
                //}
            }
        };
    }

Но после этого Тоста, если я сделаю снимок, onEvent никогда не срабатывает. Это определяется путем отладки. Он никогда не попадает в точку останова, и Тост никогда не срабатывает.

Когда этот каталог просматривается, новое изображение сохраняется там.

Как вы получаете FileObserver, работающий в Service?

4b9b3361

Ответ 1

Пожалуйста, см. этот пост. Я думаю, что вам не хватает вызова observer.startWatching() после настройки вашего наблюдателя.

 observer = new FileObserver(pathToWatch) { // set up a file observer to watch this directory on sd card

     @Override
     public void onEvent(int event, String file) {
         //if(event == FileObserver.CREATE && !file.equals(".probe")){ // check if its a "create" and not equal to .probe because thats created every time camera is launched
         Log.d(TAG, "File created [" + pathToWatch + file + "]");

         Toast.makeText(getBaseContext(), file + " was saved!", Toast.LENGTH_LONG).show();
         //}
     }
 };
 observer.startWatching(); //START OBSERVING 

Ответ 2

Добавьте .show() после toast, то есть

Toast.makeText(getBaseContext(), file + " was saved!", toast.LENGTH_LONG).show();                  

Ответ 3

Еще одна вещь, FileObserver не наблюдает подкаталог. Если вы хотите наблюдать подкаталоги тоже Проверьте этот пост.

RecursiveFileObserver с открытым исходным кодом действует как расширенный FileObserver, который является рекурсивным для всех каталогов ниже выбранного вами каталога.

package com.owncloud.android.utils;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

import android.os.FileObserver;

public class RecursiveFileObserver extends FileObserver {

    public static int CHANGES_ONLY = CLOSE_WRITE | MOVE_SELF | MOVED_FROM;

    List<SingleFileObserver> mObservers;
    String mPath;
    int mMask;

    public RecursiveFileObserver(String path) {
        this(path, ALL_EVENTS);
    }

    public RecursiveFileObserver(String path, int mask) {
        super(path, mask);
        mPath = path;
        mMask = mask;
    }

    @Override
    public void startWatching() {
        if (mObservers != null) return;
        mObservers = new ArrayList<SingleFileObserver>();
        Stack<String> stack = new Stack<String>();
        stack.push(mPath);

        while (!stack.empty()) {
            String parent = stack.pop();
            mObservers.add(new SingleFileObserver(parent, mMask));
            File path = new File(parent);
            File[] files = path.listFiles();
            if (files == null) continue;
            for (int i = 0; i < files.length; ++i) {
                if (files[i].isDirectory() && !files[i].getName().equals(".")
                    && !files[i].getName().equals("..")) {
                    stack.push(files[i].getPath());
                }
            }
        }
        for (int i = 0; i < mObservers.size(); i++)
            mObservers.get(i).startWatching();
    }

    @Override
    public void stopWatching() {
        if (mObservers == null) return;

        for (int i = 0; i < mObservers.size(); ++i)
            mObservers.get(i).stopWatching();

        mObservers.clear();
        mObservers = null;
    }

    @Override
    public void onEvent(int event, String path) {

    }

    private class SingleFileObserver extends FileObserver {
        private String mPath;

        public SingleFileObserver(String path, int mask) {
            super(path, mask);
            mPath = path;
        }

        @Override
        public void onEvent(int event, String path) {
            String newPath = mPath + "/" + path;
            RecursiveFileObserver.this.onEvent(event, newPath);
        } 

    }
}

Источник на GitHub

Ответ 4

Вот полный код для создания службы, которая прослушивает новый файл в каталоге.

Во-первых, вам нужно создать сервис, который прослушивает новую запись файла в каталоге. (Например, камера)

MediaListenerService.java


import android.app.Service;
import android.content.Intent;
import android.os.FileObserver;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;
import java.io.File;

    public class MediaListenerService extends Service {

        public static FileObserver observer;

        public MediaListenerService() {
        }

        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }

        @Override
        public void onCreate() {
            super.onCreate();
            startWatching();
        }

        private void startWatching() {

        //The desired path to watch or monitor
        //E.g Camera folder
            final String pathToWatch = android.os.Environment.getExternalStorageDirectory().toString() + "/DCIM/Camera/";
            Toast.makeText(this, "My Service Started and trying to watch " + pathToWatch, Toast.LENGTH_LONG).show();

            observer = new FileObserver(pathToWatch, FileObserver.ALL_EVENTS) { // set up a file observer to watch this directory
                @Override
                public void onEvent(int event, final String file) {
                    if (event == FileObserver.CREATE || event == FileObserver.CLOSE_WRITE || event == FileObserver.MODIFY || event == FileObserver.MOVED_TO && !file.equals(".probe")) { // check that it not equal to .probe because thats created every time camera is launched
                        Log.d("MediaListenerService", "File created [" + pathToWatch + file + "]");

                        new Handler(Looper.getMainLooper()).post(new Runnable() {
                            @Override
                            public void run() {
                                Toast.makeText(getBaseContext(), file + " was saved!", Toast.LENGTH_LONG).show();


                            }
                        });
                    }
                }
            };
            observer.startWatching();
        }
    }

Следующим шагом вам нужно объявить службу в AndroidManifest.xml внутри тега

<service
    android:name=".service.MediaListenerService"
    android:enabled="true"
    android:exported="false" >
</service>

А также не забудьте добавить разрешение:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

Если вы пишете для Android 6 или более поздней версии, вам также потребуется динамически запрашивать разрешение в соответствии с этими инструкциями: https://developer.android.com/training/permissions/requesting

Теперь запустите сервис из вашей активности.

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    startService(new Intent(getBaseContext(), MediaListenerService.class));
}

Если вы хотите, чтобы ваш сервис запускался при загрузке, просто создайте приемник, который прослушивает android.intent.action.BOOT_COMPLETED, а затем запустите сервис из этого.

Надеюсь это поможет.