Запуск службы, когда экран устройства разблокирован на Android
Я хотел бы запустить свою службу, когда экран разблокирован и остановится, когда экран заблокирован. Я изучил эти ответы и реализовал их. Однако, когда я блокирую свой экран, служба останавливается по мере необходимости, но когда я разблокирую экран, он не запускается снова.
Код для запуска этой службы следующий:
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);
}
}
}
Тогда почему это так, что когда я разблокирую свой телефон, служба не запускается снова?
Ответы
Ответ 1
Прежде всего, невозможно обнаружить, если пользователь разблокировал телефон до тех пор, пока у вас не будет 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
}
}
}
}
Ответ 2
Это потому, что вы регистрируете свой приемник внутри своей службы, который является компонентом, подобным активности, которая имеет жизненный цикл, и когда она уничтожает ваш широковещательный прослушиватель, тоже идет с ним. На самом деле, я предполагаю, что вы тоже просачиваете свое обслуживание, потому что вы не отменили регистрацию, это еще одна проблема.
Поскольку API 26 aka Oreo вы не можете зарегистрировать прослушиватель вещания в AndroidManifest.xml
, если вы хотите настроить таргетинг на API 26+, лучше всего зарегистрировать его в своем классе Application, но помните, когда система убивает ваше приложение, вы потеряете свой широковещательный прослушиватель тоже. Однако, если вы используете службу переднего плана, система не будет убивать вашу службу.
Изменить: Вот пример:
import android.app.Application;
import android.content.Intent;
import android.content.IntentFilter;
/**
* @author : [email protected]
* 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: Еще одно решение, немного взломанное, нацелено на более низкую версию API и регистрирует ваш слушатель внутри файла манифеста.
Похоже, что таргетинг на более низкий API отсутствует. Кажется, Google понимает, что некоторые разработчики будут использовать его, чтобы обойти это.