Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
187 views
in Technique[技术] by (71.8m points)

android - How to monitor folder for file changes in background?

I am trying to monitor a folder on the users disk in the background, much like how you can monitor gallery changes with a JobScheduler and contentobserver. I want to do this for any specified directory. However, I cannot figure out how to receive a broadcast when the directory has any file changes.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

There are several things you have to do in order create a system wide file observer.

Firstly

You have to create a service that will start up at boot and will always be running. In order for this to happen you have to create a BroadcastReceiver, register it to receive ACTION_BOOT_COMPLETED and the RECEIVE_BOOT_COMPLETED permission to your Manifest

public class StartupReceiver extends BroadcastReceiver {   

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

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

    }
}

In your 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>

Secondly

The service has to implement the android.os.FileObserver class. As android.os.FileObserver only observes the path you send to it and does not observe the path's subdirectories, you have to extend it and add SingleFileObserver observers to it. You also have to run the observation in another thread with priority set to low

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

     }

 }

That's it With this code you'll be able to observe the entire file system, both the internal and external file systems


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...