使用 START_STICKY 或 START_NOT_STICKY 保持后台服务不起作用
Posted
技术标签:
【中文标题】使用 START_STICKY 或 START_NOT_STICKY 保持后台服务不起作用【英文标题】:Keep Background Service using START_STICKY or START_NOT_STICKY doesn't work 【发布时间】:2018-06-26 04:25:12 【问题描述】:我创建了一个使用服务在后台运行CountDownTimer
的应用程序。
但是当应用关闭/终止时,后台服务有时会失败或自行停止。
我曾尝试使用START_STICKY
或START_NOT_STICK
,但仍然无法正常工作,无法保持服务CountDownTimer
处于活动状态。 (this the different of them)
我也尝试了我在 *** 上找到的所有建议,但同样不起作用。
这是我的代码:
SessionTimerService.java
public class SessionTimerService extends Service
private CountDownTimer countDownTimer;
public static boolean isServiceRunning = false;
@Override
public void onCreate()
super.onCreate();
startTimer();
@Override
public void onDestroy()
isServiceRunning = false;
super.onDestroy();
@Override
public int onStartCommand(Intent intent, int flags, int startId)
if(intent!=null && intent.getAction().equals(Constant.ACTION_START_SERVICE))
startTimer();
else
stopTimer();
return START_STICKY;
private void stopTimer()
stopForeground(true);
stopSelf();
isServiceRunning = false;
private void startTimer()
if(isServiceRunning)return;
isServiceRunning = true;
String formatCountDown = "%02d:%02d:%02d";
countDownTimer = new CountDownTimer(TimeUnit.MINUTES.toMillis(1), 1000)
@Override
public void onTick(long millisUntilFinished)
String time = ""+String.format(formatCountDown,
TimeUnit.MILLISECONDS.toHours(millisUntilFinished),
TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished) - TimeUnit.HOURS.toMinutes(
TimeUnit.MILLISECONDS.toHours(millisUntilFinished)),
TimeUnit.MILLISECONDS.toSeconds(millisUntilFinished) - TimeUnit.MINUTES.toSeconds(
TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished)));
Timber.d("The Time : " + time);
Intent broadcast = new Intent(Constant.EVENT_SESSION_TIMER);
broadcast.putExtra(Constant.BROADCAST_TIMER, time);
LocalBroadcastManager.getInstance(App.getInstance().getApplicationContext()).sendBroadcast(broadcast);
@Override
public void onFinish()
Toast.makeText(SessionTimerService.this, "Timer ended!", Toast.LENGTH_SHORT).show();
;
countDownTimer.start();
@Nullable
@Override
public IBinder onBind(Intent intent)
return null;
App.java
我从应用程序启动CountDownTimer
。这里是代码:
public class App extends Application
private ApplicationComponent applicationComponent;
private static boolean isChatActivityOpen = false;
private static boolean isSendChat = false;
private static App instanceApp;
private CountDownTimer countDownTimer;
private Handler handler = new Handler();
@Override
public void onCreate()
super.onCreate();
Fabric.with(this, new Crashlytics());
Timber.plant(new Timber.DebugTree());
instanceApp = this;
// TODO: Add this project to your fabric.io
/*Crashlytics crashlyticsKit = new Crashlytics.Builder()
.core(new CrashlyticsCore.Builder().disabled(BuildConfig.DEBUG).build())
.build();
Fabric.with(this, crashlyticsKit);*/
if (applicationComponent == null)
applicationComponent = DaggerApplicationComponent.builder()
.applicationModule(new ApplicationModule(App.get(this)))
.build();
public static App get(Context context)
return (App) context.getApplicationContext();
public ApplicationComponent getComponent()
return applicationComponent;
public static boolean isChatActivityOpen()
return isChatActivityOpen;
public static boolean isSendChat()
return isSendChat;
public static synchronized App getInstance()
return instanceApp;
public void setConnectivityListener(ConnectivityReceiver.ConnectivityReceiverListener listener)
ConnectivityReceiver.connectivityReceiverListener = listener;
public static void setChatActivityOpen(boolean isChatActivityOpen)
App.isChatActivityOpen = isChatActivityOpen;
public static void setSendChatStatus(boolean isSendChat)
App.isSendChat = isSendChat;
public void startTimer()
Intent intent = new Intent(getInstance().getApplicationContext(), SessionTimerService.class);
intent.setAction(Constant.ACTION_START_SERVICE);
startService(intent);
public void stopTimer()
Intent intent = new Intent(getInstance().getApplicationContext(), SessionTimerService.class);
intent.setAction(Constant.ACTION_STOP_SERVICE);
stopService(intent);
@Override
public void onTerminate()
super.onTerminate();
要在我的活动中启动计时器,我执行以下操作:
App.startTimer()
或 App.stopTimer()
注意:我在活动中调用App.startTimer()
。
请帮助修复此错误。谢谢你。
【问题讨论】:
【参考方案1】:如果您的目标是 android 8+,this is an intended behaviour
您的后台服务将在几分钟后被终止。
如果您以 8 之前的版本为目标:
您应该在 Application 类的 onCreate 中使用 startTimer。
如果您将服务设为 Sticky,服务将在终止后重新启动应用程序上下文,并且只执行应用程序类的 onCreate 内的内容。
如果您将 startTimer 保留在 Activity 中,它将在前台按意图启动,并且一旦被杀死就不会重新创建自己。
【讨论】:
我使用最小 SDK 版本 17。我也做startTimer()
内部活动。但是正如你所说,服务在几分钟后就被杀死了,如何解决这个问题?
或者您可以创建通知并将服务作为前台服务启动
或者如我所说,在 Application 类的 onCreate 中执行 startTimer。一旦你杀死你的应用程序,这将是你保持服务存活的唯一方法
@Flowwlol :那么如何从活动触发到应用程序的onCreate?你能把代码剪掉吗?【参考方案2】:
这取决于你想用你的服务做什么。
如果您希望您的服务在您的应用被终止时运行,这就是将要发生的事情:
应用程序正在运行 -> 被杀死 -> 上下文被破坏 -> 服务在应用程序被杀死时重新启动应用程序,从那里,只有应用程序上下文将处于活动状态,因此您的应用程序中唯一会发生的事情就是 onCreate 中发生的事情应用类。 一旦你杀死你的应用程序,一切都会被破坏,然后它会尝试重新创建它的一部分。
因此,一旦你杀死你的应用程序,它就不会重新创建一个 Activity,也不会重新创建你的服务。
因此,如果您希望在特定 Activity 中启动服务,则一旦您终止应用,该服务将无法工作。
public class App extends Application
private ApplicationComponent applicationComponent;
private static boolean isChatActivityOpen = false;
private static boolean isSendChat = false;
private static App instanceApp;
private CountDownTimer countDownTimer;
private Handler handler = new Handler();
@Override
public void onCreate()
super.onCreate();
Fabric.with(this, new Crashlytics());
Timber.plant(new Timber.DebugTree());
instanceApp = this;
startTimer();
// TODO: Add this project to your fabric.io
/*Crashlytics crashlyticsKit = new Crashlytics.Builder()
.core(new CrashlyticsCore.Builder().disabled(BuildConfig.DEBUG).build())
.build();
Fabric.with(this, crashlyticsKit);*/
if (applicationComponent == null)
applicationComponent = DaggerApplicationComponent.builder()
.applicationModule(new ApplicationModule(App.get(this)))
.build();
【讨论】:
将startTimer()
放在onCreate 中是很好的解决方案,但它会从头开始重新启动计时器。有什么办法可以让定时器正常运行而不重启?
@NiA 您可以使用SharedPref
将计时器状态(即其值)保存在变量中,然后从该特定状态重新启动计时器【参考方案3】:
你可以这样做:
-
仅启动服务而不将其绑定到活动
同时启动一个通知服务,即使应用程序被强制关闭,它也会继续运行
【讨论】:
我已经尝试过你的线索,即使我创建了显示计时器的通知,服务仍然强制。 服务什么时候停止?一段时间后或应用程序被强制关闭时? 当应用程序被杀死时,先生。我使用startForeground(1, notification)
。我的意思是,当应用程序被终止时,计时器不再运行
一旦服务被强制停止,您可以重新启动服务,您可以使用BroadcastReciever
,这是一个链接:***.com/a/21551045/8311441以上是关于使用 START_STICKY 或 START_NOT_STICKY 保持后台服务不起作用的主要内容,如果未能解决你的问题,请参考以下文章