【问题标题】:Android - implementing startForeground for a service?Android - 为服务实现 startForeground?
【发布时间】:2011-09-17 20:55:53
【问题描述】:

所以我不确定在哪里/如何实现此方法以使我的服务在前台运行。目前我在另一个活动中通过以下方式开始我的服务:

Intent i = new Intent(context, myService.class); 
context.startService(i);

然后在 myServices 的 onCreate() 中尝试 startForeground()...?

Notification notification = new Notification();
startForeground(1, notification);

所以是的,我有点迷茫,不确定如何实现这一点。

【问题讨论】:

标签: android service android-service


【解决方案1】:

我会先完全填写NotificationHere is a sample project 演示startForeground() 的使用。

【讨论】:

  • 是否可以在不通知的情况下使用 startForeground() ?或者我们可以稍后更新相同的通知吗?
  • 你使用1337有什么特别的原因吗?
  • @DoctorOreo:它需要在应用程序中是唯一的,但在设备上不一定是唯一的。我选择了 1337,因为它是1337。 :-)
  • @JRC 问题很好。是否可以在不通知的情况下使用 startForeground()?
  • @Snicolas:感谢您指出 Android 中的一个缺陷。我会努力解决这个问题。
【解决方案2】:

在您的主要活动中,使用以下代码启动服务:

Intent i = new Intent(context, MyService.class); 
context.startService(i);

然后在您为onCreate() 服务时,您将构建您的通知并将其设置为前台,如下所示:

Intent notificationIntent = new Intent(this, MainActivity.class);

PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
                notificationIntent, 0);

Notification notification = new NotificationCompat.Builder(this)
                .setSmallIcon(R.mipmap.app_icon)
                .setContentTitle("My Awesome App")
                .setContentText("Doing some work...")
                .setContentIntent(pendingIntent).build();

startForeground(1337, notification);

【讨论】:

  • @mike 如何从 MainActivity 更新此通知?
  • @Roon13 使用 ID,在本例中为 1337 ...您应该能够构建新通知并使用 ID 调用 startForeground
  • @Roon13 看看这个问题stackoverflow.com/questions/5528288/…
  • @mikebertiean 如何从 MainActivity 调用 startForeground?进程完成后如何清除 MainActvity 的通知?
  • 别忘了:
【解决方案3】:

奥利奥8.1解决方案

我遇到了一些问题,例如 RemoteServiceException,因为最新版本的 Android 的频道 ID 无效。我就是这样解决的:

活动

override fun onCreate(savedInstanceState: Bundle?) {
    val intent = Intent(this, BackgroundService::class.java)

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        startForegroundService(intent)
    } else {
        startService(intent)
    }
}

后台服务:

override fun onCreate() {
    super.onCreate()
    startForeground()
}

private fun startForeground() {

  
    val channelId =
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                createNotificationChannel()
            } else {
                // If earlier version channel ID is not used
                // https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html#NotificationCompat.Builder(android.content.Context)
                ""
            }

    val notificationBuilder = NotificationCompat.Builder(this, channelId )
    val notification = notificationBuilder.setOngoing(true)
            .setSmallIcon(R.mipmap.ic_launcher)
            .setPriority(PRIORITY_MIN)
            .setCategory(Notification.CATEGORY_SERVICE)
            .build()
    startForeground(101, notification)
}


@RequiresApi(Build.VERSION_CODES.O)
private fun createNotificationChannel(): String{
    val channelId = "my_service"
    val channelName = "My Background Service"
    val chan = NotificationChannel(channelId,
            channelName, NotificationManager.IMPORTANCE_HIGH)
    chan.lightColor = Color.BLUE
    chan.importance = NotificationManager.IMPORTANCE_NONE
    chan.lockscreenVisibility = Notification.VISIBILITY_PRIVATE
    val service = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
    service.createNotificationChannel(chan)
    return channelId
}

JAVA 等价物

public class YourService extends Service {

    // Constants
    private static final int ID_SERVICE = 101;
    
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        super.onStartCommand(intent, flags, startId);
        return START_STICKY;
    }

    @Override
    public void onCreate() {
        super.onCreate();

        // do stuff like register for BroadcastReceiver, etc.

        // Create the Foreground Service
        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        String channelId = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ? createNotificationChannel(notificationManager) : "";
        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, channelId);
        Notification notification = notificationBuilder.setOngoing(true)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setPriority(PRIORITY_MIN)
                .setCategory(NotificationCompat.CATEGORY_SERVICE)
                .build();

        startForeground(ID_SERVICE, notification);
    }
    
    @RequiresApi(Build.VERSION_CODES.O)
    private String createNotificationChannel(NotificationManager notificationManager){
        String channelId = "my_service_channelid";
        String channelName = "My Foreground Service";
        NotificationChannel channel = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_HIGH);
        // omitted the LED color
        channel.setImportance(NotificationManager.IMPORTANCE_NONE);
        channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
        notificationManager.createNotificationChannel(channel);
        return channelId;
    }
}

【讨论】:

  • 您可以在您的活动中使用ContextCompat.startForegroundService(Context,Intent),这将做正确的事情。 (developer.android.com/reference/android/support/v4/content/…)
  • 如果您的最小 API ,您可能希望使用 .setCategory(NotificationCompat.CATEGORY_SERVICE) 而不是 Notification.CATEGORY_SERVICE
  • 请注意,针对Build.VERSION_CODES.P(API 级别 28)或更高版本的应用必须请求Manifest.permission.FOREGROUND_SERVICE 的权限才能使用startForeground() - 请参阅developer.android.com/reference/android/app/…
【解决方案4】:

这是我将服务设置为前台的代码:

private void runAsForeground(){
    Intent notificationIntent = new Intent(this, RecorderMainActivity.class);
    PendingIntent pendingIntent=PendingIntent.getActivity(this, 0,
            notificationIntent, Intent.FLAG_ACTIVITY_NEW_TASK);

    Notification notification=new NotificationCompat.Builder(this)
                                .setSmallIcon(R.drawable.ic_launcher)
                                .setContentText(getString(R.string.isRecording))
                                .setContentIntent(pendingIntent).build();

    startForeground(NOTIFICATION_ID, notification);

}

我需要使用 PendingIntent 构建一个通知,以便我可以从该通知开始我的主要活动。

要删除通知,只需调用 stopForeground(true);

它在 onStartCommand() 中被调用。请参考我的代码:https://github.com/bearstand/greyparrot/blob/master/src/com/xiong/richard/greyparrot/Mp3Recorder.java

【讨论】:

  • 如果您删除调用 stopForeground(true) 的通知,您将取消 startforeground 服务
  • 你从哪里调用这个方法?
  • Intent.FLAG_ACTIVITY_NEW_TASKPendingIntent 的上下文中无效。
【解决方案5】:

除了RAWA回答,本和平代码:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    startForegroundService(intent)
} else {
    startService(intent)
}

你可以改成:

ContextCompat.startForegroundService(context, yourIntent);

如果你看一下这个方法,你会发现这个方法为你做了所有的检查工作。

【讨论】:

    【解决方案6】:

    如果你想让 IntentService 成为前台服务

    那么你应该像这样覆盖onHandleIntent()

    Override
    protected void onHandleIntent(@Nullable Intent intent) {
    
    
        startForeground(FOREGROUND_ID,getNotification());     //<-- Makes Foreground
    
       // Do something
    
        stopForeground(true);                                // <-- Makes it again a normal Service                         
    
    }
    
       
    

    如何通知?

    简单。这里是getNotification() 方法

    public Notification getNotification()
    {
    
        Intent intent = new Intent(this, SecondActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this,0,intent,0);
    
    
        NotificationCompat.Builder foregroundNotification = new NotificationCompat.Builder(this);
        foregroundNotification.setOngoing(true);
    
        foregroundNotification.setContentTitle("MY Foreground Notification")
                .setContentText("This is the first foreground notification Peace")
                .setSmallIcon(android.R.drawable.ic_btn_speak_now)
                .setContentIntent(pendingIntent);
    
    
        return foregroundNotification.build();
    }
    

    深入了解

    当服务变成前台服务时会发生什么

    发生这种情况

    什么是前台服务?

    前台服务,

    • 确保用户主动意识到后台正在发生的事情 通过提供通知。

    • (最重要的是)在内存不足时不会被系统杀死

    前台服务用例

    Implementing song download functionality in a Music App

    【讨论】:

      【解决方案7】:

      在 onCreate() 中为“OS >= Build.VERSION_CODES.O”添加给定的代码服务类

      @Override
      public void onCreate(){
          super.onCreate();
      
           .................................
           .................................
      
          //For creating the Foreground Service
          NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
          String channelId = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ? getNotificationChannel(notificationManager) : "";
          NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, channelId);
          Notification notification = notificationBuilder.setOngoing(true)
                  .setSmallIcon(R.mipmap.ic_launcher)
                 // .setPriority(PRIORITY_MIN)
                  .setCategory(NotificationCompat.CATEGORY_SERVICE)
                  .build();
      
          startForeground(110, notification);
      }
      
      
      
      @RequiresApi(Build.VERSION_CODES.O)
      private String getNotificationChannel(NotificationManager notificationManager){
          String channelId = "channelid";
          String channelName = getResources().getString(R.string.app_name);
          NotificationChannel channel = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_HIGH);
          channel.setImportance(NotificationManager.IMPORTANCE_NONE);
          channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
          notificationManager.createNotificationChannel(channel);
          return channelId;
      }
      

      在清单文件中添加此权限:

       <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
      

      【讨论】:

        【解决方案8】:

        使用 startCommand 处理服务意图。

         stopForeground(true)
        

        此调用将从前台状态中删除服务,如果需要更多内存,则可以将其终止。 这不会停止服务运行。为此,您需要调用 stopSelf() 或相关方法。

        传递值 truefalse 指示是否要删除通知。

        val ACTION_STOP_SERVICE = "stop_service"
        val NOTIFICATION_ID_SERVICE = 1
        ...  
        override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
            super.onStartCommand(intent, flags, startId)
            if (ACTION_STOP_SERVICE == intent.action) {
                stopForeground(true)
                stopSelf()
            } else {
                //Start your task
        
                //Send forground notification that a service will run in background.
                sendServiceNotification(this)
            }
            return Service.START_NOT_STICKY
        }
        

        stopSelf() 调用销毁时处理您的任务。

        override fun onDestroy() {
            super.onDestroy()
            //Stop whatever you started
        }
        

        创建通知以保持服务在前台运行。

        //This is from Util class so as not to cloud your service
        fun sendServiceNotification(myService: Service) {
            val notificationTitle = "Service running"
            val notificationContent = "<My app> is using <service name> "
            val actionButtonText = "Stop"
            //Check android version and create channel for Android O and above
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                //You can do this on your own
                //createNotificationChannel(CHANNEL_ID_SERVICE)
            }
            //Build notification
            val notificationBuilder = NotificationCompat.Builder(applicationContext, CHANNEL_ID_SERVICE)
            notificationBuilder.setAutoCancel(true)
                    .setDefaults(NotificationCompat.DEFAULT_ALL)
                    .setWhen(System.currentTimeMillis())
                    .setSmallIcon(R.drawable.ic_location)
                    .setContentTitle(notificationTitle)
                    .setContentText(notificationContent)
                    .setVibrate(null)
            //Add stop button on notification
            val pStopSelf = createStopButtonIntent(myService)
            notificationBuilder.addAction(R.drawable.ic_location, actionButtonText, pStopSelf)
            //Build notification
            val notificationManagerCompact = NotificationManagerCompat.from(applicationContext)
            notificationManagerCompact.notify(NOTIFICATION_ID_SERVICE, notificationBuilder.build())
            val notification = notificationBuilder.build()
            //Start notification in foreground to let user know which service is running.
            myService.startForeground(NOTIFICATION_ID_SERVICE, notification)
            //Send notification
            notificationManagerCompact.notify(NOTIFICATION_ID_SERVICE, notification)
        }
        

        在通知上提供停止按钮以在用户需要时停止服务。

        /**
         * Function to create stop button intent to stop the service.
         */
        private fun createStopButtonIntent(myService: Service): PendingIntent? {
            val stopSelf = Intent(applicationContext, MyService::class.java)
            stopSelf.action = ACTION_STOP_SERVICE
            return PendingIntent.getService(myService, 0,
                    stopSelf, PendingIntent.FLAG_CANCEL_CURRENT)
        }
        

        【讨论】:

          【解决方案9】:

          注意:如果您的应用以 API 级别 26 或更高级别为目标,系统会限制使用或创建后台服务,除非应用本身位于前台。

          如果应用需要创建前台服务,应用应该调用startForegroundService()该方法创建一个后台服务,但该方法向系统发出信号,该服务将把自己提升到前景。

          服务创建后,服务必须调用其startForeground() method within five seconds.

          【讨论】:

          • 我希望你在谈论当前的问题。否则,Stackoverflow 社区没有这样的规则
          • @RogerGusmao 在生产环境代码中不会总是保存您的项目。此外 - 在我的答案下方和上方有很多很好的示例代码。我的项目在发布期间出现问题正是因为我不知道 startForegroundService 方法
          【解决方案10】:

          就我而言,情况完全不同,因为我没有在 Oreo 上启动该服务的活动。

          以下是我用来解决此前台服务问题的步骤 -

          public class SocketService extends Service {
              private String TAG = this.getClass().getSimpleName();
          
              @Override
              public void onCreate() {
                  Log.d(TAG, "Inside onCreate() API");
                  if (Build.VERSION.SDK_INT >= 26) {
                      NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this);
                      mBuilder.setSmallIcon(R.drawable.ic_launcher);
                      mBuilder.setContentTitle("Notification Alert, Click Me!");
                      mBuilder.setContentText("Hi, This is Android Notification Detail!");
                      NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
          
                      // notificationID allows you to update the notification later on.
                      mNotificationManager.notify(100, mBuilder.build());
                      startForeground(100, mBuilder.mNotification);
                  }
                  Toast.makeText(getApplicationContext(), "inside onCreate()", Toast.LENGTH_LONG).show();
              }
          
          
              @Override
              public int onStartCommand(Intent resultIntent, int resultCode, int startId) {
                  Log.d(TAG, "inside onStartCommand() API");
          
                  return startId;
              }
          
          
              @Override
              public void onDestroy() {
                  super.onDestroy();
                  Log.d(TAG, "inside onDestroy() API");
          
              }
          
              @Override
              public IBinder onBind(Intent intent) {
                  // TODO Auto-generated method stub
                  return null;
              }
          }
          

          然后启动这个服务,我在 cmd 下触发 -


          adb -s " + serial_id + " shell am startforegroundservice -n com.test.socket.sample/.SocketService


          所以这有助于我在奥利奥设备上不活动的情况下启动服务:)

          【讨论】:

            【解决方案11】:

            @mikebertiean 解决方案几乎成功了,但我遇到了额外的问题——我使用 Gingerbread 系统,我不想添加一些额外的包来运行通知。最后我发现: https://android.googlesource.com/platform/frameworks/support.git+/f9fd97499795cd47473f0344e00db9c9837eea36/v4/gingerbread/android/support/v4/app/NotificationCompatGingerbread.java

            然后我遇到了其他问题——通知只是在我的应用程序运行时杀死了它(如何解决这个问题:Android: How to avoid that clicking on a Notification calls onCreate()),所以总的来说我的服务代码看起来像这样(C#/Xamarin):

            Intent notificationIntent = new Intent(this, typeof(MainActivity));
            // make the changes to manifest as well
            notificationIntent.SetFlags(ActivityFlags.ClearTop | ActivityFlags.SingleTop);
            PendingIntent pendingIntent = PendingIntent.GetActivity(this, 0, notificationIntent, 0);
            Notification notification = new Notification(Resource.Drawable.Icon, "Starting service");
            notification.SetLatestEventInfo(this, "MyApp", "Monitoring...", pendingIntent);
            StartForeground(1337, notification);
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2014-01-20
              • 2015-02-23
              • 1970-01-01
              相关资源
              最近更新 更多