我想运行一个Backgroundservice(FileObserver),它将查找系统中的任何文件更改(CREATE,DELETE,MOVE等)。 当我启动我的应用程序时,它可以工作几秒钟,并且一切正常。例如,在用相机拍摄照片时,它会记录下来。几秒钟后,该服务仍列在“设置” =>“开发人员选项” =>“运行服务”中,但不再起作用并且不再记录任何内容。
Android版本:7.0
设备:三星Galaxy S7 Edge
我在这里1:1复制了Niza Siwale的答案中的代码,并仅添加了这样的日志:
How to monitor folder for file changes in background?
@Override
public void onEvent(int event, final String path) {
if (event == FileObserver.OPEN) {
Log.v("Event: ", "Open" + path);
} else if (event == FileObserver.CREATE && (!path.equals(".probe"))) {
Log.v("Event: ", "Create" + path);
} else if (event == FileObserver.DELETE_SELF || event == FileObserver.DELETE) {
Log.v("Event: ", "Delete" + path);
} else if (event == FileObserver.MOVE_SELF || event == FileObserver.MOVED_FROM || event == FileObserver.MOVED_TO) {
Log.v("Event: ", "Move" + path);
}
}
如果文件系统发生某些变化,为什么服务在后台运行(如我在“运行服务”中所看到的),却不放弃任何日志?
完整代码:
清单
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.spicysoftware.phonesaver">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<!-- Adding the permission -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<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>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
MainActivity
package com.spicysoftware.phonesaver;
import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Environment;
import android.os.FileObserver;
import android.os.Handler;
import android.os.Looper;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
String TAG = "Log: ";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(isReadStoragePermissionGranted()){
Intent myIntent = new Intent(this, FileSystemObserverService.class);
this.startService(myIntent);
}
}
public boolean isReadStoragePermissionGranted() {
if (Build.VERSION.SDK_INT >= 23) {
if (checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED) {
Log.v(TAG,"Permission is granted1");
return true;
} else {
Log.v(TAG,"Permission is revoked1");
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 3);
return false;
}
}
else { //permission is automatically granted on sdk<23 upon installation
Log.v(TAG,"Permission is granted1");
return true;
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case 3:
Log.d(TAG, "External storage1");
if(grantResults[0]== PackageManager.PERMISSION_GRANTED){
Log.v(TAG,"Permission: "+permissions[0]+ "was "+grantResults[0]);
}else{
}
break;
}
}
}
FileSystemOberveService
package com.spicysoftware.phonesaver;
import android.app.Service;
import android.content.Intent;
import android.os.Environment;
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;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
public class FileSystemObserverService extends Service {
String externalPath = "";
String internalPath = "";
@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) {
Log.v("Event: ", "Open" + path);
// makeToast("Opened: "+path);
} else if (event == FileObserver.CREATE && (!path.equals(".probe"))) {
Log.v("Event: ", "Create" + path);
// makeToast("Created: "+path);
} else if (event == FileObserver.DELETE_SELF || event == FileObserver.DELETE) {
Log.v("Event: ", "Delete" + path);
// makeToast("Deleted: "+path);
} else if (event == FileObserver.MOVE_SELF || event == FileObserver.MOVED_FROM || event == FileObserver.MOVED_TO) {
Log.v("Event: ", "Move" + path);
// makeToast("Moved: "+path);
}
}
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);
}
}
}
/*
public void makeToast(final String strMessage){
//Let this be the code in your n'th level thread from main UI thread
Handler h = new Handler(Looper.getMainLooper());
h.post(new Runnable() {
public void run() {
Toast.makeText(getApplicationContext(), strMessage, Toast.LENGTH_SHORT).show();
}
});
}
*/
}
StartupReceiver
package com.spicysoftware.phonesaver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class StartupReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Intent myIntent = new Intent(context, FileSystemObserverService.class);
context.startService(myIntent);
}
}