FileObserver callback 不会触发(stackoverflow 的相关话题中有详细提到)

FileObserver callback won't trigger (Related topics on stackoverflow mentioned in details)

我正在尝试监听外部存储目录中的任何事件,即通过 Android FileObserver 添加、删除或修改文件,但它的 onEvent 方法从未被调用。

我已经尝试了以下所有解决方案:

Android FileObserver [duplicate]

FileObserver instance is being garbage collected

How do you implement a FileObserver from an Android Service

至于我的代码,如下所示:

清单

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.grapgame.fileobserverdemo">

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

<application
    android:name=".AppClass"
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <service android:name=".FileObserverService" />
</application>

</manifest>

服务

public class FileObserverService extends Service {

public static final String TAG = "FileObserverService";

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    Log.d(TAG, "onStart");

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

    AppClass.fileObserver = new FileObserver(pathToWatch) { // set up a file observer to watch this directory on sd card
        @Override
        public void onEvent(int event, String file) {
            Log.d(TAG, "File created [" + pathToWatch + file + "]");
        }
    };
    AppClass.fileObserver.startWatching();
    return START_STICKY;
}

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

AppClass.java

public class AppClass extends Application {
    public static FileObserver fileObserver;

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

MainActivity.java

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Intent intent = new Intent(this, FileObserverService.class);
        startService(intent);
    }
}

我也试过没有AppClass.java,我在Whosebug上找到了这个解决方案并试过了。我也尝试了这个 GitHub 代码,但似乎没有任何效果。

我知道 FileObserver 不是递归的,现在我只是想听一个目录。

非常感谢任何帮助。

在 RecursiveFileObserver

下面使用 class
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

import android.os.FileObserver;
import android.util.Log;

public class RecursiveFileObserver extends FileObserver {
    /**
     * Only modification events
     */
    public static int CHANGES_ONLY = CREATE | DELETE | CLOSE_WRITE | MOVE_SELF | MOVED_FROM | MOVED_TO;

    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.isEmpty()) {
            String parent = stack.pop();
            mObservers.add(new SingleFileObserver(parent, mMask));
            File path = new File(parent);
            File[] files = path.listFiles();
            if (null == files) continue;
            for (File f : files) {
                if (f.isDirectory() && !f.getName().equals(".") && !f.getName().equals("..")) {
                    stack.push(f.getPath());
                }
            }
        }

        for (SingleFileObserver sfo : mObservers) {
            sfo.startWatching();
        }
    }

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

        for (SingleFileObserver sfo : mObservers) {
            sfo.stopWatching();
        }
        mObservers.clear();
        mObservers = null;
    }

    @Override
    public void onEvent(int event, String path) {
        switch (event) {
            case FileObserver.CREATE:
                Log.i("RecursiveFileObserver", "CREATE: " + path);

                break;
            case FileObserver.MODIFY:
                Log.i("RecursiveFileObserver", "MODIFY: " + path);
                break;
        }
    }

    /**
     * Monitor single directory and dispatch all events to its parent, with full path.
     *
     * @author uestc.Mobius <mobius@toraleap.com>
     * @version 2011.0121
     */
    class SingleFileObserver extends FileObserver {
        String mPath;

        public SingleFileObserver(String path) {
            this(path, ALL_EVENTS);
            mPath = path;
        }

        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);
        }
    }
}

您的服务将如下所示

import android.app.Service;
import android.content.Intent;
import android.os.Environment;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;

import java.io.File;

public class FileObserverService extends Service {

    public static final String TAG = "FileObserverService";

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "onStartCommand: Service Started");
        File sdCard = Environment.getExternalStorageDirectory();
        AppClass.fileObserver = new RecursiveFileObserver(sdCard.getAbsolutePath());
        AppClass.fileObserver.startWatching();
        return START_STICKY;
    }

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

    @Override
    public void onDestroy() {
        Log.d(TAG, "onDestroy: Service Destroyed");
    }
}

和像这样的 AppClass

public class AppClass extends Application {
    public static RecursiveFileObserver fileObserver;

    @Override
    public void onCreate() {
        super.onCreate();
        Intent intent = new Intent(this, FileObserverService.class);
        startService(intent);
    }
}