如何从Android服务实现FileObserver

如何构建Android应用程序以启动Service以使用FileObserver以便在观察目录被修改时(即用户拍照)执行其他一些代码。 调试时,永远不会触发onEvent方法。

这是我服务中的onStart事件。 Toast为“我的服务开始……”开火

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

但是在Toast之后,如果我拍照,onEvent永远不会发射。 这是通过调试确定的。 它永远不会击中那个断点,Toast永远不会发射。

浏览该目录时,新图像将保存在那里。

如何在Service使用FileObserver

请看这篇文章。 我认为你在设置观察者后缺少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 

toast后添加.show() ,即

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

FileObserver还没有观察到子目录。 如果你想观察子目录,请查看这篇文章。

开源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 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(); Stack stack = new Stack(); 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

以下是创建侦听目录中新文件的服务的完整代码。

首先,您需要创建在目录中侦听新文件条目的服务。 (例如相机)

 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 //Eg 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内部标记声明服务

   

并且不要忘记添加权限:

  

如果您是为Android 6或更高版本编写的,则还需要动态请求权限,具体如下: https : //developer.android.com/training/permissions/requesting

现在从您的Activity启动服务。

 @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的接收器,然后从中启动服务。

希望这可以帮助。