即使应用程序被杀,我也希望在后台运行IntentService
。并且“被杀”是指长按主页按钮 - > 查看所有正在运行的应用 - > 将我的应用扫到一边 - > app killed 或长按后退按钮 - > app killed
我的代码如下。在我的MainActivity中:
Intent intent = new Intent(this, MyService.class);
this.startService(intent);
在我的MyService中:
public class MyService extends IntentService {
@Override
protected void onHandleIntent(Intent intent) {
System.out.println("MyService started");
run();
}
private void run() {
while (true){
System.out.println("MyService still running");
doSomething();
waitSomeTime();
}
}
}
当应用程序打开时,我看到该服务正在运行。当我通过主页按钮最小化应用时,它仍在运行。当我通过后退按钮关闭应用时,它仍然在运行。但如果我如上所述杀死它,它就会停止。我该如何解决这个问题?
答案 0 :(得分:27)
如果您的应用启动了您的服务,那么实际上您的服务正在主进程上运行。因此,当应用程序被杀死时,服务也将被停止。所以你可以做的是,从服务的onTaskRemoved
方法发送广播,如下所示:
Intent intent = new Intent("com.android.ServiceStopped");
sendBroadcast(intent);
并有一个广播接收器,它将再次启动服务。我试过了。服务从所有类型的杀戮中重新开始。
答案 1 :(得分:18)
所有答案似乎都是正确,所以我将在此处给出完整答案。
首先,最简单的方法是尝试手动杀死 app 并在Android中启动 Broadcast ,然后定义自定义 BroadcastReceiver
之后触发服务重启。
现在让我们进入代码。
在YourService.java
请注意onCreate()
方法,在此方法中,对于大于 Android Oreo 的Build版本,我们将以不同的方式启动前景服务。这是因为最近引入了严格的通知政策,我们必须定义自己的通知渠道才能正确显示它们。
this.sendBroadcast(broadcastIntent);
方法中的onDestroy()
是一条语句,它以动作名称 "restartservice"
异步发送广播。稍后我们将以此为触发来重新启动我们的服务。
我们在这里定义了一个简单的Timer任务,该任务每 1秒在 Log
中打印一个计数器值,而每次打印时都会递增。 / p>
public class YourService extends Service {
public int counter=0;
@Override
public void onCreate() {
super.onCreate();
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O)
startMyOwnForeground();
else
startForeground(1, new Notification());
}
@RequiresApi(Build.VERSION_CODES.O)
private void startMyOwnForeground()
{
String NOTIFICATION_CHANNEL_ID = "example.permanence";
String channelName = "Background Service";
NotificationChannel chan = new NotificationChannel(NOTIFICATION_CHANNEL_ID, channelName, NotificationManager.IMPORTANCE_NONE);
chan.setLightColor(Color.BLUE);
chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
assert manager != null;
manager.createNotificationChannel(chan);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID);
Notification notification = notificationBuilder.setOngoing(true)
.setContentTitle("App is running in background")
.setPriority(NotificationManager.IMPORTANCE_MIN)
.setCategory(Notification.CATEGORY_SERVICE)
.build();
startForeground(2, notification);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
startTimer();
return START_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
stoptimertask();
Intent broadcastIntent = new Intent();
broadcastIntent.setAction("restartservice");
broadcastIntent.setClass(this, Restarter.class);
this.sendBroadcast(broadcastIntent);
}
private Timer timer;
private TimerTask timerTask;
public void startTimer() {
timer = new Timer();
timerTask = new TimerTask() {
public void run() {
Log.i("Count", "========= "+ (counter++));
}
};
timer.schedule(timerTask, 1000, 1000); //
}
public void stoptimertask() {
if (timer != null) {
timer.cancel();
timer = null;
}
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
创建广播接收器以响应Restarter.java
您刚刚在"restartservice"
中定义的动作名称 YourService.java
的广播现在应该触发一种方法,该方法将重新启动服务 。这是在Android中使用 BroadcastReceiver
完成的。
我们覆盖了 onRecieve()
中的内置BroadcastReceiver
方法,以添加将重新启动服务的语句。 startService()
在Android Oreo 8.1及更高版本中将无法正常工作,因为一旦应用被终止,严格的后台策略将在重启后立即终止服务。因此,我们将startForegroundService()
用于更高版本,并显示连续的通知以保持服务运行。
public class Restarter extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.i("Broadcast Listened", "Service tried to stop");
Toast.makeText(context, "Service restarted", Toast.LENGTH_SHORT).show();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(new Intent(context, YourService.class));
} else {
context.startService(new Intent(context, YourService.class));
}
}
}
定义您的MainActivity.java
,以便在应用启动时调用该服务。
在这里,我们定义了一个单独的isMyServiceRunning()
方法来检查后台服务的当前状态。如果该服务未运行 ,我们将使用startService()
启动该服务。
由于该应用程序已经在前台运行,因此我们无需将其作为前台服务启动,以防止自身被终止。
请注意,在onDestroy()
中,我们专门调用stopService()
,以便调用我们的 覆盖的方法 。如果未执行此操作,则该服务将在终止应用程序后自动 终止,而无需调用 onDestroy()
public class MainActivity extends AppCompatActivity {
Intent mServiceIntent;
private YourService mYourService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mYourService = new YourService();
mServiceIntent = new Intent(this, mYourService.getClass());
if (!isMyServiceRunning(mYourService.getClass())) {
startService(mServiceIntent);
}
}
private boolean isMyServiceRunning(Class<?> serviceClass) {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
Log.i ("Service status", "Running");
return true;
}
}
Log.i ("Service status", "Not running");
return false;
}
@Override
protected void onDestroy() {
stopService(mServiceIntent);
super.onDestroy();
}
}
最后将它们注册到您的AndroidManifest.xml
以上三个类别中的所有类别都需要分别在 AndroidManifest.xml
中注册。
请注意,我们定义的intent-filter
的操作名称为"restartservice"
,其中 Restarter.java
被注册为{{ 1}}。
这样可以确保在系统遇到具有给定动作名称的广播时,都会调用我们的自定义 receiver
。
BroadcastReciever
现在,如果应用程序已从任务管理器中终止,这应该再次重新启动服务。只要用户未从应用程序设置中通过 <application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<receiver
android:name="Restarter"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="restartservice" />
</intent-filter>
</receiver>
<activity android:name="MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name="YourService"
android:enabled="true" >
</service>
</application>
应用程序,该服务将继续在后台运行。
更新:对Dr.jacky表示赞赏。上面提到的方法仅在调用服务的Force Stop
时才有效,在某些时候可能不是,这是我不知道的。谢谢。
答案 2 :(得分:5)
在onstart命令中放置START_STICKY
...除非执行太多任务并且内核想要为它杀死它,否则此服务不会被杀死...
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("LocalService", "Received start id " + startId + ": " + intent);
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
return START_STICKY;
}
答案 3 :(得分:4)
原因是您正在尝试使用IntentService。以下是API Docs
中的一行IntentService执行以下操作:
在处理完所有启动请求后停止服务,所以你 永远不必调用stopSelf()。
因此,如果您希望您的服务无限期运行,我建议您扩展Service类。但是,这并不能保证您的服务无限期运行。如果内存处于低优先级状态,你的服务仍然有可能被内核杀死。所以你有两个选择:
1)通过调用startForeground()
方法使其在前台运行
2)如果服务被杀,请重新启动服务。
以下是文档中的一部分示例,其中讨论了在服务被杀后重新启动服务
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
// For each start request, send a message to start a job and deliver the
// start ID so we know which request we're stopping when we finish the job
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
// If we get killed, after returning from here, restart
return START_STICKY;
}
答案 4 :(得分:4)
在您的服务中,添加以下代码。
@Override
public void onTaskRemoved(Intent rootIntent){
Intent restartServiceIntent = new Intent(getApplicationContext(), this.getClass());
restartServiceIntent.setPackage(getPackageName());
PendingIntent restartServicePendingIntent = PendingIntent.getService(getApplicationContext(), 1, restartServiceIntent, PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmService = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
alarmService.set(
AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime() + 1000,
restartServicePendingIntent);
super.onTaskRemoved(rootIntent);
}
答案 5 :(得分:2)
您可以在清单中使用android:stopWithTask="false"
,这意味着即使用户通过从任务列表中删除应用来杀死应用,您的服务也不会停止。
<service android:name=".service.StickyService"
android:stopWithTask="false"/>
答案 6 :(得分:0)
在您的服务类中使用 onTaskRemoved
@Override
public void onTaskRemoved(Intent rootIntent) {
Intent restartServiceIntent = new Intent(getApplicationContext(), this.getClass());
PendingIntent restartServicePendingIntent = PendingIntent.getService(
getApplicationContext(), 1, restartServiceIntent, PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmService = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmService.set(AlarmManager.ELAPSED_REALTIME, elapsedRealtime() + 500,
restartServicePendingIntent);
Log.d("taskremoved", "task removed ");
super.onTaskRemoved(rootIntent);
}
答案 7 :(得分:0)
你试试下面的代码:
public class HeartbeartService extends Service {
private static final int SERVICE_NOTIFICATION_ID = 54321;
private static final String CHANNEL_ID = "Notification service";
private final LocalBinder mBinder = new LocalBinder();
Handler handler = new Handler();
private Runnable runnableCode = new Runnable() {
@Override
public void run() {
Context context = getApplicationContext();
Intent myIntent = new Intent(context, HeartbeatEventService.class);
context.startService(myIntent);
HeadlessJsTaskService.acquireWakeLockNow(context);
handler.postDelayed(this, 2000);
}
};
public class LocalBinder extends Binder {
public HeartbeartService getService() {
return HeartbeartService.this;
}
}
private void createNotificationChannel() {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
int importance = NotificationManager.IMPORTANCE_MIN;
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "Notification service", importance);
channel.setDescription("CHANEL DESCRIPTION");
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onDestroy() {
super.onDestroy();
this.handler.removeCallbacks(this.runnableCode);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
this.handler.post(this.runnableCode);
createNotificationChannel();
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent,
PendingIntent.FLAG_CANCEL_CURRENT);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Notification service")
.setContentText("Running...")
.setBadgeIconType(0)
.setAutoCancel(false)
.setOngoing(true)
.build();
startForeground(1, notification);
return START_STICKY;
}
}