如何保持Android多线程FileObserver前台服务持续运行?
Hey there! I see you're building an Android app to monitor the entire file system, and you've got a foreground service set up but it won't run permanently. Let's break down the issues and fix them step by step.
1. Fix the Service Restart Behavior
Right now, your onStartCommand returns the default value from super.onStartCommand(), which doesn’t tell the system to restart your service if it gets killed. You need to change this return value to ensure the service sticks around:
@Override public int onStartCommand(Intent intent, int flags, int startId) { observe(); // Use START_STICKY to restart the service if it's killed by the system return START_STICKY; // Or use START_REDELIVER_INTENT if you need to re-send the original intent on restart // return START_REDELIVER_INTENT; }
START_STICKY tells Android to restart your service with a null intent if it’s terminated due to resource constraints—perfect for a monitoring service that doesn’t rely on specific intent data.
2. Handle Dynamic Directory Changes
Your current Observer only scans directories once when startWatching() is called. If new directories are created later, they won’t be monitored. Update your onEvent method to add observers for newly created directories:
Modify your Observer class's onEvent method:
@Override public void onEvent(int event, final String path) { if (event == FileObserver.OPEN) { writeLog("OPEN", path); } else if (event == FileObserver.CREATE && (!path.equals(".probe"))) { writeLog("CREATE", path); // Check if the created item is a directory, then add a new observer File newDir = new File(path); if (newDir.isDirectory()) { SingleFileObserver newObserver = new SingleFileObserver(path, mMask); mObservers.add(newObserver); newObserver.startWatching(); } } else if (event == FileObserver.DELETE_SELF || event == FileObserver.DELETE) { writeLog("DELETE", path); } else if (event == FileObserver.MOVE_SELF || event == FileObserver.MOVED_FROM || event == FileObserver.MOVED_TO) { writeLog("MOVE", path); } }
This way, any new directories created after the service starts will automatically be added to your monitoring list.
3. Bypass Battery Optimization Restrictions
Android 8.0 (API 26+) and later have strict battery optimization policies that can kill even foreground services if the app is deemed idle. You need to request the user to exclude your app from battery optimization:
First, add this permission to your AndroidManifest.xml:
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
Then, add code to prompt the user to disable battery optimization (call this when the service starts or the app is first launched):
private void requestBatteryOptimizationExemption() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { Intent intent = new Intent(); String packageName = getPackageName(); PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); if (!pm.isIgnoringBatteryOptimizations(packageName)) { intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS); intent.setData(Uri.parse("package:" + packageName)); startActivity(intent); } } }
4. Ensure Boot Completion Setup
You mentioned the service is set to start on boot—double-check you have all pieces in place:
- Add the boot permission to
AndroidManifest.xml:<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> - Create a broadcast receiver to start your service on boot:
public class BootReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) { Intent serviceIntent = new Intent(context, FileSystemObserverService.class); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { context.startForegroundService(serviceIntent); } else { context.startService(serviceIntent); } } } } - Register the receiver in
AndroidManifest.xml:<receiver android:name=".BootReceiver"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter> </receiver>
5. Minor Logging Improvement
Your writeLog method opens and closes the file every time an event occurs, which can be inefficient. Use try-with-resources to avoid resource leaks and simplify the code:
public void writeLog(final String event, final String path){ String filename = getFilesDir().toString() + "/log.txt"; String to_write = event + " " + path + "\n"; try (BufferedWriter bw = new BufferedWriter(new FileWriter(filename, true))) { bw.write(to_write); } catch (Exception e){ e.printStackTrace(); Log.i("onEvent","Exception Error: " + e.getMessage()); } }
Putting all these changes together should make your service run much more reliably, even through system restarts and resource constraints.
内容的提问来源于stack exchange,提问作者Kigael Lee

