我想在屏幕解锁时运行我的服务,并在屏幕锁定时停止它。我调查了these answers并实施了它们。 但是,当我锁定屏幕时,服务会根据需要停止,但是当我解锁屏幕时,它不会再次启动。
运行此服务的代码如下:
public class PhonePositionService extends Service {
@Override
public void onCreate() {
//ADDED CODE
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
BroadcastReceiver mReceiver = new BootCompletedIntentReceiver();
registerReceiver(mReceiver, filter);
{...}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
int icon = R.drawable.ic_stat_bright;
startForeground(NOTIFICATION_ID, getCompatNotification(icon));
if (backgroundThread != null) {
backgroundThread.start();
}
return START_STICKY;
}
}
在其他一些文件中,我的广播接收器代码如下:
public class BootCompletedIntentReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(Intent.ACTION_SCREEN_ON.equals(action)) {
// start the service
Intent pushIntent = new Intent(context, PhonePositionService.class);
context.startService(pushIntent);
} else if(Intent.ACTION_SCREEN_OFF.equals(action)) {
// stop the service
Intent pushIntent = new Intent(context, PhonePositionService.class);
context.stopService(pushIntent);
}
if ("android.intent.action.BOOT_COMPLETED".equals(intent.getAction())) {
Intent pushIntent = new Intent(context, PhonePositionService.class);
context.startService(pushIntent);
}
}
}
那么为什么当我解锁手机时服务不会再次启动呢?
答案 0 :(得分:9)
首先,在您拥有Admin Privilages之前,无法检测用户是否已解锁手机。您遇到的问题是因为您在屏幕关闭时使用PhonePositionService
停止stopService()
:
public class BootCompletedIntentReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(Intent.ACTION_SCREEN_ON.equals(action)) {
// start the service
Intent pushIntent = new Intent(context, PhonePositionService.class);
context.startService(pushIntent);
} else if(Intent.ACTION_SCREEN_OFF.equals(action)) {
// stop the service
Intent pushIntent = new Intent(context, PhonePositionService.class);
//This will stop the service
context.stopService(pushIntent);
}
if ("android.intent.action.BOOT_COMPLETED".equals(intent.getAction())) {
Intent pushIntent = new Intent(context, PhonePositionService.class);
context.startService(pushIntent);
}
}
}
由于BroadcastReceiver未注册,因此会导致内存泄漏。
不鼓励将服务永久保持在前台运行,因为它可能会导致(快速)电池耗尽。
我建议你找其他选择。但是,如果您的核心功能受到影响并且您仍想继续,则可以执行以下操作:
将BootCompletedIntentReceiver
设为PhonePositionService
的内部类。而不是启动和停止服务,而是直接执行您的操作。
public class PhonePositionService extends Service {
@Override
public void onCreate() {
//ADDED CODE
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
BroadcastReceiver mReceiver = new BootCompletedIntentReceiver();
registerReceiver(mReceiver, filter);
...
}
...
private class BootCompletedIntentReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(Intent.ACTION_SCREEN_ON.equals(action)) {
//DO action for SCREEN_ON
} else if(Intent.ACTION_SCREEN_OFF.equals(action)) {
//Do action for SCREEN_OFF
}
}
}
}
答案 1 :(得分:2)
那是因为你在你的服务中注册你的接收器,这是一个像生命周期活动的组件,当它被摧毁你的广播听众时也是如此。实际上我猜你也在这里泄露你的服务,因为你没有注销它,这是另一个问题。
自API 26又名Oreo you cannot register you broadcast listener inside AndroidManifest.xml
以来,如果您想要定位API 26+,最好的办法是在应用类中注册它,但要注意当系统杀死你的应用时你也会丢失你的广播听众。但是,如果您使用前台服务,系统将无法终止您的服务。
修改强> 这是一个例子:
import android.app.Application;
import android.content.Intent;
import android.content.IntentFilter;
/**
* @author : M.Reza.Nasirloo@gmail.com
* Created on: 2018-04-12
*/
public class App extends Application {
@Override
public void onCreate() {
super.onCreate();
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_SCREEN_ON);
registerReceiver(new BootCompletedIntentReceiver(), filter);
}
}
不要忘记在清单文件中设置此类。
<application
android:name=".App"
android:allowBackup="true"
请注意,您需要始终运行前台服务,以免错过事件。
PS:还有一个有点hacky的解决方案,针对较低的API版本并在清单文件中注册你的监听器。
看起来定位较低的API不合适。谷歌似乎知道一些开发人员会用它来解决这个问题。