安卓服务需要一直运行(永不暂停或停止)

75

我创建了一个服务,并希望让这个服务一直运行,直到我的手机重新启动或强制关闭。该服务应在后台运行。

创建服务的示例代码及启动服务:

启动服务:

Intent service = new Intent(getApplicationContext(), MyService.class);
getApplicationContext().startService(service);

该服务:

public class MyService extends Service {

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // TODO do something useful
        HFLAG = true;
        //smsHandler.sendEmptyMessageDelayed(DISPLAY_DATA, 1000);
        return Service.START_NOT_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO for communication return IBinder implementation
        return null;
    }
}

清单声明:

<service
    android:name=".MyService"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name" >
</service>

如何使得服务在应用程序暂停或其他情况下一直运行? 经过一段时间后,我的应用程序会暂停并且服务也会暂停或者停止。 那么我该如何让这个服务在后台一直运行呢?


1
不将其作为系统映像的一部分,无法实现此操作。在某些情况下,Android可能会完全终止您的应用程序。当您的应用程序被杀死时,它的服务将不再存在。 - StarPinkER
2
谢谢回复,我该如何将我的应用程序作为系统镜像的一部分。 - Ashekur Rahman Molla Asik
你需要修改固件。如果可以的话,我可以写一个答案。 - StarPinkER
你可以这样做,例如检查来电时服务是否正在运行,如果没有,则重新启动它...同样的方式使用媒体扫描器完成、启动完成、收到短信等等。你必须每次都检查你的服务是否正在运行,就像Watsup Massage服务一样。但我不建议你这样做。有关更多详细信息,请参阅:https://dev59.com/72025IYBdhLWcg3wSkAq#6091362和https://dev59.com/oW855IYBdhLWcg3wbjnO#4353653。 - Dhaval Parmar
9个回答

95

如何在应用程序暂停和其他情况下始终运行此服务?

是可以的。

  1. 在服务的onStartCommand方法中返回START_STICKY。

public int onStartCommand(Intent intent, int flags, int startId) {
        return START_STICKY;
}
  • 使用 startService(MyService) 在后台启动该服务,使其始终保持活动状态,而不受绑定客户端数量的影响。

  • Intent intent = new Intent(this, PowerMeterService.class);
    startService(intent);
    
    创建绑定器。
    public class MyBinder extends Binder {
            public MyService getService() {
                    return MyService.this;
            }
    }
    
  • 定义一个服务连接。

    private ServiceConnection m_serviceConnection = new ServiceConnection() {
            public void onServiceConnected(ComponentName className, IBinder service) {
                    m_service = ((MyService.MyBinder)service).getService();
            }
    
            public void onServiceDisconnected(ComponentName className) {
                    m_service = null;
            }
    };
    
  • 使用 bindService 绑定服务。

            Intent intent = new Intent(this, MyService.class);
            bindService(intent, m_serviceConnection, BIND_AUTO_CREATE);
    
  • 对于您的服务,您可能希望在其关闭后通过通知来启动相应的活动。

  • private void addNotification() {
            // create the notification
            Notification.Builder m_notificationBuilder = new Notification.Builder(this)
                    .setContentTitle(getText(R.string.service_name))
                    .setContentText(getResources().getText(R.string.service_status_monitor))
                    .setSmallIcon(R.drawable.notification_small_icon);
    
            // create the pending intent and add to the notification
            Intent intent = new Intent(this, MyService.class);
            PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
            m_notificationBuilder.setContentIntent(pendingIntent);
    
            // send the notification
            m_notificationManager.notify(NOTIFICATION_ID, m_notificationBuilder.build());
    }
    
    你需要修改清单文件,以在 single top 模式下启动该活动。
              android:launchMode="singleTop"
    
    请注意,如果系统需要资源并且您的服务不活跃,则可能会被终止。如果无法接受这种情况,请使用startForeground将服务置于前台。
            startForeground(NOTIFICATION_ID, m_notificationBuilder.build());
    

    通过这种方式,该服务一段时间后会自动进入睡眠状态。 - Ashekur Rahman Molla Asik
    1
    非常好的答案 - 它完美地解决了问题。许多其他类似问题的答案都是部分的,而这个答案是完整的。 - Andrew Alcock
    24
    请问您能详细说明第八条吗?它在哪里执行?另外关于第五条,它是否在启动服务的同一位置执行?我理解您的意思是使用通知来始终保持服务处于运行状态,是这样吗? - Tom
    2
    @Stephen Donecker 为什么我必须绑定它? - Silvia H
    2
    @SilviaHisham,你不需要绑定。通常在服务需要与活动通信时才进行绑定。 - Tim
    显示剩余11条评论

    8
    为了在自己的进程中启动服务,您必须在xml声明中指定以下内容。
    <service
      android:name="WordService"
      android:process=":my_process" 
      android:icon="@drawable/icon"
      android:label="@string/service_name"
      >
    </service> 
    

    这里有一篇对我来说非常有用的好教程,涉及到IT技术。

    http://www.vogella.com/articles/AndroidServices/article.html

    希望这能帮到你。


    android:name="WordService" 是指 MyService 吗? - Ashekur Rahman Molla Asik
    1
    是的,你需要输入自己的名字。 - Juan
    @juan:你需要查看这个链接:http://developer.android.com/guide/topics/manifest/service-element.html - Dhaval Parmar
    @Juan:这意味着您的服务在单独的线程中运行。这并不意味着您无法停止它。 - Dhaval Parmar
    他需要的服务不能停止,即使有人停止它。然后它会在一段时间后自动启动。我们可以使用android:process=":my_process"来实现这个功能吗? - Dhaval Parmar
    显示剩余4条评论

    3

    如果你已经拥有一个服务并希望它一直工作,你需要添加两件事情:

    1. in the service itself:

      public int onStartCommand(Intent intent, int flags, int startId) {
          return START_STICKY;
      }
      
    2. In the manifest:

      android:launchMode="singleTop"
      

    除非您在服务中需要它,否则无需添加绑定。


    将targetSdkVersion设置为30后无法正常工作。情况1:将应用程序保持在后台超过1分钟:服务被终止。情况2:应用程序被终止:服务被终止。 - Shanki Bansal

    3

    当系统停止服务时,一个简单的解决方案是重新启动该服务。

    我发现了这种方法的一个非常简单的实现:

    如何使Android服务不可阻止


    在 Android O 中,后台不允许广播接收器启动服务,那这个怎么工作的呢? - famfamfam
    将targetSdkVersion设置为30后无法正常工作。情况1:将应用程序保持在后台超过3分钟:服务被终止。情况2:当应用程序被终止时:服务被终止。 - Shanki Bansal

    2

    您可以为服务实现startForeground,即使它死亡,您也可以在startCommand()上使用START_STICKY来重新启动它。不过,我不确定这是否是正确的实现方式。


    没有START_STICKY也可以正常工作,当targetSdkVersion = 30时。 - Shanki Bansal

    0

    4
    在Android O中,不允许后台广播接收器启动服务,那么它是如何工作的? - Michael

    0

    -1

    我已经克服了这个问题,我的示例代码如下。

    在您的主活动中添加以下行,其中BackGroundClass是服务类。您可以在新建 -> JavaClass中创建此类(在此类中,将需要在后台发生的过程(任务)添加到其中)。 为方便起见,首先用通知铃声将它们标注为后台进程。

     startService(new Intent(this, BackGroundClass .class));
    

    在BackGroundClass中,只需包含我的代码,您就可以看到结果。
    import android.app.Service;
    import android.content.Intent;
    import android.media.MediaPlayer;
    import android.os.IBinder;
    import android.provider.Settings;
    import android.support.annotation.Nullable;
    import android.widget.Toast;
    
    public class BackgroundService  extends Service {
        private MediaPlayer player;
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
    @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
         player = MediaPlayer.create(this,Settings.System.DEFAULT_RINGTONE_URI);
            player.setLooping(true);
             player.start();
            return START_STICKY;
        }
     @Override
        public void onDestroy() {
            super.onDestroy();
             player.stop();
        }
    }
    

    在 AndroidManifest.xml 中,尝试添加这个。
    <service android:name=".BackgroundService"/>
    

    运行程序,只需打开应用程序,您可能会在后台找到通知警报。即使您退出应用程序,但除非您关闭应用程序或卸载应用程序,否则仍可能听到铃声警报。这表示通知警报处于后台进程中。像这样,您可以为后台添加一些进程。
    注意:请不要使用TOAST进行验证,因为它只会运行一次,即使它在后台进程中也是如此。
    希望这有所帮助...!!

    不,这段代码不起作用。onStartCommand 只被调用了一次。 - Gaju Kollur
    我发了一个问题 https://stackoverflow.com/questions/49922332/onstartcommand-is-calling-only-once-in-service-android/49925704#49925704 - Gaju Kollur

    -1

    在清单文件中添加此内容。

          <service
            android:name=".YourServiceName"
            android:enabled="true"
            android:exported="false" />
    

    添加一个服务类。
    public class YourServiceName extends Service {
    
    
        @Override
        public void onCreate() {
            super.onCreate();
    
          // Timer task makes your service will repeat after every 20 Sec.
           TimerTask doAsynchronousTask = new TimerTask() {
                @Override
                public void run() {
                    handler.post(new Runnable() {
                        public void run() {
                           // Add your code here.
    
                         }
    
                   });
                }
            };
      //Starts after 20 sec and will repeat on every 20 sec of time interval.
            timer.schedule(doAsynchronousTask, 20000,20000);  // 20 sec timer 
                                  (enter your own time)
        }
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            // TODO do something useful
    
          return START_STICKY;
        }
    
    }
    

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接