2017-12-30 241 views
5

Próbuję monitorować folder na dysku użytkownika w tle, podobnie jak można monitorować zmiany galerii za pomocą JobScheduler i contentobserver. Chcę to zrobić dla dowolnego określonego katalogu. Nie mogę jednak dowiedzieć się, jak odebrać transmisję, gdy katalog zawiera jakiekolwiek zmiany plików.Jak monitorować folder zmiany plików w tle?

+2

'android.os.FileObserver'? – pskink

+0

Podaj przykład, jak wyzwalać to w tle automatycznie @pskink –

+2

Czy przeczytałeś dokumentację javadoc? jeśli tak, z czym masz problemy? – pskink

Odpowiedz

2

Po prostu uruchom usługę, która używa Fileobserver do wykrywania zmian w pliku dla określonego katalogu.

Klasa usługi:

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

Uruchom usługę z gdzieś wewnątrz aplikacji z YOUR_FILEPATH/katalogu, który chcesz obserwować:

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

to pomija część, w której potrzebuję jej do uruchomienia w dowolnym momencie zmiany pliku na tej ścieżce. Nie można uruchomić usługi 24/7. –

+0

Jeśli nie możesz uruchomić usługi, nie ma możliwości ciągłego monitorowania operacji przechowywania danych poza modyfikacją oprogramowania układowego. Nawet stworzona usługa może być słabsza od zasobów. Inną możliwością jest Menedżer alarmów, który okresowo skanuje katalog w poszukiwaniu zmian, z wybranym przez użytkownika czasem odpytywania, aby mógł kontrolować zużycie baterii i procesora przez aplikację. Ale nie jesteś w stanie natychmiast wykryć zmian w pliku. – matthiasT

4

istnieje kilka rzeczy, które trzeba zrobić w celu stworzenia systemowy obserwator plików.

pierwsze

Trzeba stworzyć usługę, która rozpocznie się w bagażniku i zawsze będzie uruchomiony. Aby tak się stało trzeba stworzyć BroadcastReceiver, zarejestruj je otrzymać ACTION_BOOT_COMPLETED i pozwolenie RECEIVE_BOOT_COMPLETED do Manifest

public class StartupReceiver extends BroadcastReceiver { 

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

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

    } 
} 

w twojej 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> 

drugie

Usługa musi implementować klasę android.os.FileObserver. Jako że android.os.FileObserver obserwuje tylko ścieżkę, którą do niej wysyłasz i nie obserwuje podkatalogów ścieżki, musisz ją rozszerzyć i dodać do niej obserwatorów SingleFileObserver. Trzeba też uruchomić obserwację w innym wątku z priorytetem ustawionym na niskim

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

       } 

     } 

to wszystko Z tego kodu będzie można obserwować cały system plików, zarówno wewnętrzne jak i zewnętrzne systemy plików

+0

Czy usługa nie zostanie ostatecznie zabita przez system, jeśli nie działa jako usługa pierwszego planu? –