web-dev-qa-db-ja.com

AndroidサービスからFileObserverをどのように実装しますか

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は発生しません。これはデバッグによって決定されます。そのブレークポイントに到達することはなく、トーストは決して発火しません。

そのディレクトリを参照すると、新しい画像がそこに保存されます。

どのようにFileObserverServiceで動作させるのですか?

28
shanabus

参照 この投稿をご覧ください。オブザーバーをセットアップした後、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 
48
Jack

toastの後に.show()を追加します。

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

もう1つFileObserverはサブディレクトリを監視しません。サブディレクトリも監視したい場合は、 this の投稿を確認してください。

オープンソース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
Vivek Bansal

以下は、ディレクトリ内の新しいファイルをリッスンするサービスを作成するための完全なコードです。

まず、ディレクトリ内の新しいファイルエントリをリッスンするサービスを作成する必要があります。 (例:カメラ)

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's 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/トレーニング/許可/リクエスト

次に、アクティビティからサービスを開始します。

@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をリッスンするレシーバーを作成し、そこからサービスを起動するだけです。

お役に立てれば。

2
Oyewo Remi