【问题标题】:Starting a service when the device's screen is unlocked in Android在 Android 中解锁设备屏幕时启动服务
【发布时间】:2018-04-10 05:53:55
【问题描述】:

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

那为什么当我解锁手机时服务没有重新启动?

【问题讨论】:

  • 您可以通过关注answer添加更多回调来检索用户操作

标签: android service


【解决方案1】:

首先,在您拥有管理员权限之前,它无法检测用户是否已解锁手机。您面临的问题是因为您在屏幕关闭时使用stopService() 停止PhonePositionService

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 又名 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:还有另一个解决方案有点老套,针对较低的 API 版本并在清单文件中注册您的侦听器。

    看起来定位较低的 API 不可行。谷歌似乎知道一些开发人员会使用它来解决这个问题。

    【讨论】:

    • 我取消注册它的 onDestroy() 函数。在示例代码中,我看到它们都在 onCreate 函数(活动或服务)中调用了 registerReceiver()。那我应该在哪里注册呢?您能否在答案中提供一些代码示例。
    • @Sarahcartenz 我在答案中添加了示例代码。
    猜你喜欢
    • 1970-01-01
    • 2012-05-30
    • 2021-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多