在Android中解锁设备的屏幕时启动服务

时间:2018-04-10 05:53:55

标签: android service

我想在屏幕解锁时运行我的服务,并在屏幕锁定时停止它。我调查了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);
  }
 }
}

那么为什么当我解锁手机时服务不会再次启动呢?

2 个答案:

答案 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不合适。谷歌似乎知道一些开发人员会用它来解决这个问题。