【问题标题】:How to monitor folder for file changes in background?如何在后台监控文件夹的文件更改?
【发布时间】:2019-05-17 00:56:24
【问题描述】:

我正在尝试在后台监控用户磁盘上的文件夹,就像您如何使用 JobSchedulercontentobserver 监控图库更改一样。我想对任何指定的目录执行此操作。但是,当目录有任何文件更改时,我无法弄清楚如何接收广播。

【问题讨论】:

  • android.os.FileObserver ?
  • 您阅读过 javadoc 文档吗?如果是这样,你有什么问题?
  • 然后使用Services
  • 阅读android.app.Servicejavadocs
  • 那么到目前为止你用 FileObserver 做了什么?

标签: android


【解决方案1】:

为了创建系统范围的文件观察器,您必须做几件事。

首先

您必须创建一个将在启动时启动并始终运行的服务。 为此,您必须创建一个BroadcastReceiver,注册它以接收ACTION_BOOT_COMPLETEDRECEIVE_BOOT_COMPLETED 对您的Manifest 的权限

public class StartupReceiver extends BroadcastReceiver {   

    @Override
    public void onReceive(Context context, Intent intent) {

     Intent myIntent = new Intent(context, FileSystemObserverService.class);
     context.startService(myIntent);

    }
}

在你的Manifest

<manifest >
    <application >

    <service
        android:name=".FileSystemObserverService"
        android:enabled="true"
        android:exported="true" >
    </service>
    <!-- Declaring broadcast receiver for BOOT_COMPLETED event. -->
        <receiver android:name=".StartupReceiver" android:enabled="true" android:exported="false">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
            </intent-filter>
        </receiver>

    </application>

    <!-- Adding the permission -->
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

</manifest>

其次

服务必须实现android.os.FileObserver 类。由于android.os.FileObserver 只观察您发送给它的路径而不观察路径的子目录,因此您必须对其进行扩展并向其添加SingleFileObserver 观察者。您还必须在优先级设置为低的另一个线程中运行观察

        public class FileSystemObserverService extends Service {

 @Override
 public IBinder onBind(Intent intent) {
     // TODO: Return the communication channel to the service.
     throw new UnsupportedOperationException("Not yet implemented");
 }

 @Override
 public int onStartCommand(Intent intent, int flags, int startId) {
     observe();
     return super.onStartCommand(intent, flags, startId);
 }

 public File getInternalStoragePath() {
     File parent = Environment.getExternalStorageDirectory().getParentFile();
     File external = Environment.getExternalStorageDirectory();
     File[] files = parent.listFiles();
     File internal = null;
     if (files != null) {
         for (int i = 0; i < files.length; i++) {
             if (files[i].getName().toLowerCase().startsWith("sdcard") && !files[i].equals(external)) {
                 internal = files[i];
             }
         }
     }

     return internal;
 }
 public File getExtenerStoragePath() {

     return Environment.getExternalStorageDirectory();
 }

 public void observe() {
     Thread t = new Thread(new Runnable() {

         @Override
         public void run() {


             //File[]   listOfFiles = new File(path).listFiles();
             File str = getInternalStoragePath();
             if (str != null) {
                 internalPath = str.getAbsolutePath();

                 new Obsever(internalPath).startWatching();
             }
             str = getExtenerStoragePath();
             if (str != null) {

                 externalPath = str.getAbsolutePath();
                 new Obsever(externalPath).startWatching();
             }



         }
     });
     t.setPriority(Thread.MIN_PRIORITY);
     t.start();


 }

 class Obsever extends FileObserver {

     List < SingleFileObserver > mObservers;
     String mPath;
     int mMask;
     public Obsever(String path) {
         // TODO Auto-generated constructor stub
         this(path, ALL_EVENTS);
     }
     public Obsever(String path, int mask) {
         super(path, mask);
         mPath = path;
         mMask = mask;
         // TODO Auto-generated constructor stub

     }
     @Override
     public void startWatching() {
         // TODO Auto-generated method stub
         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() {
         // TODO Auto-generated method stub
         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, final String path) {
         if (event == FileObserver.OPEN) {
             //do whatever you want
         } else if (event == FileObserver.CREATE) {
             //do whatever you want
         } else if (event == FileObserver.DELETE_SELF || event == FileObserver.DELETE) {

             //do whatever you want
         } else if (event == FileObserver.MOVE_SELF || event == FileObserver.MOVED_FROM || event == FileObserver.MOVED_TO) {
             //do whatever you want

         }
     }

     private class SingleFileObserver extends FileObserver {
         private String mPath;
         public SingleFileObserver(String path, int mask) {
             super(path, mask);
             // TODO Auto-generated constructor stub
             mPath = path;
         }

         @Override
         public void onEvent(int event, String path) {
             // TODO Auto-generated method stub
             String newPath = mPath + "/" + path;
             Obsever.this.onEvent(event, newPath);
         }

     }

 }

就是这样 使用此代码,您将能够观察整个文件系统,包括内部和外部文件系统

【讨论】:

  • 如果不作为前台服务运行,服务最终会不会被系统杀死?
  • 我当然可能遗漏了一些东西,但似乎有几个问题 (1) 如果服务启动不止一次,那么看起来你最终会看到多个线程查看相同的文件无法阻止它们,因为似乎没有引用被保留,并且(2)这些“观察者”实例的范围是什么 - 似乎没有任何对它们的引用被保留在任何地方,所以它们不能在任何时候被垃圾收集时刻?
  • FileObserver 观察路径的子目录,正如developer.android.com/reference/android/os/FileObserver 写道:每个FileObserver 实例可以监控多个文件或目录。如果某个目录被监控,那么被监控目录内的所有文件和子目录都会触发事件。
  • Android 是否为此使用了 Linux inotify 模块?
  • 是的,这样的服务很容易被系统杀死。您可以创建带有通知的前台服务,然后它应该能够存活并且如果它被杀死可能会被系统重新启动。
【解决方案2】:

只需启动一个使用 Fileobserver 来检测指定目录的文件更改的服务。

服务类:

public class FileObserverService extends Service {
    private FileObserver mFileObserver;

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if((intent.hasExtra(INTENT_EXTRA_FILEPATH))) // we store the path of directory inside the intent that starts the service
        mFileObserver = new FileObserver(intent.getStringExtra(INTENT_EXTRA_FILEPATH)) {
            @Override
            public void onEvent(int event, String path) {
               // If an event happens we can do stuff inside here
               // for example we can send a broadcast message with the event-id          
               Log.d("FILEOBSERVER_EVENT", "Event with id " + Integer.toHexString(event) + " happened") // event identifies the occured Event in hex
            }
        };
        mFileObserver.startWatching(); // The FileObserver starts watching
        return Service.START_NOT_STICKY;
    }

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

    @Override
    public IBinder onBind(Intent intent) {
        //TODO for communication return IBinder implementation
        return null;
    }
}

使用您要观察的 YOUR_FILEPATH/DIRECTORY 从应用内部的某个位置启动服务:

Intent intent = new Intent(this, FileObserverService.class);
    intent.putExtra(INTENT_EXTRA_FILEPATH, "YOUR_FILEPATH");
    this.startService(intent);

【讨论】:

  • 这错过了我需要它运行的部分,只要此路径中有文件更改。不能让服务 24/7 运行
  • 如果您无法运行服务,则除了修改固件外,您没有办法持续监控外部存储操作。即使是创建的服务也可能资源不足。另一种可能性是 AlarmManager,它会定期扫描目录的更改,并由用户选择轮询周期,以便他们可以控制您的应用程序的电池和 CPU 消耗。但是您无法立即检测到文件更改。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-26
  • 2013-10-24
  • 1970-01-01
  • 2011-06-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多