我有一个从Activity启动的IntentService,我希望能够通过活动中的“取消”按钮立即停止活动。一旦按下“取消”按钮,我希望服务停止执行代码行。
我发现了许多类似的问题(例如here,here,here,here),但没有好的答案。 Activity.stopService()
和Service.stopSelf()
立即执行Service.onDestroy()
方法,但在销毁服务之前让onHandleIntent()
中的代码完成。
由于显然没有保证立即终止服务线程的方法,我能找到的唯一推荐的解决方案(here)是在服务中有一个布尔成员变量,可以在{{1方法,然后几乎在onDestroy()
中的每一行代码都包含在自己的“if”子句中查看该变量。这是编写代码的一种糟糕方式。
有人知道在IntentService中更好的方法吗?
答案 0 :(得分:30)
这是诀窍,使用易失性静态变量并在服务的某些行中检查继续条件,应检查服务继续:
class MyService extends IntentService {
public static volatile boolean shouldContinue = true;
public MyService() {
super("My Service");
}
@Override
protected void onHandleIntent(Intent intent) {
doStuff();
}
private void doStuff() {
// do something
// check the condition
if (shouldContinue == false) {
stopSelf();
return;
}
// continue doing something
// check the condition
if (shouldContinue == false) {
stopSelf();
return;
}
// put those checks wherever you need
}
}
并在您的活动中执行此操作以停止您的服务,
MyService.shouldContinue = false;
答案 1 :(得分:12)
立即停止线程或进程通常是件坏事。但是,如果您的服务是无状态的,那应该没问题。
将服务声明为清单中的单独进程:
<service
android:process=":service"
...
当你想要停止执行时,只需要杀死这个过程:
ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
List<RunningAppProcessInfo> runningAppProcesses = am.getRunningAppProcesses();
Iterator<RunningAppProcessInfo> iter = runningAppProcesses.iterator();
while(iter.hasNext()){
RunningAppProcessInfo next = iter.next();
String pricessName = getPackageName() + ":service";
if(next.processName.equals(pricessName)){
Process.killProcess(next.pid);
break;
}
}
答案 2 :(得分:5)
我在服务中使用了一个BroadcastReceiver,它只是将stop boolean设置为true。例如:
private boolean stop=false;
public class StopReceiver extends BroadcastReceiver {
public static final String ACTION_STOP = "stop";
@Override
public void onReceive(Context context, Intent intent) {
stop = true;
}
}
@Override
protected void onHandleIntent(Intent intent) {
IntentFilter filter = new IntentFilter(StopReceiver.ACTION_STOP);
filter.addCategory(Intent.CATEGORY_DEFAULT);
StopReceiver receiver = new StopReceiver();
registerReceiver(receiver, filter);
// Do stuff ....
//In the work you are doing
if(stop==true){
unregisterReceiver(receiver);
stopSelf();
}
}
然后,从活动电话:
//STOP SERVICE
Intent sIntent = new Intent();
sIntent.setAction(StopReceiver.ACTION_STOP);
sendBroadcast(sIntent);
停止服务。
PD:我使用布尔值,因为在我的情况下,我在循环中停止服务,但你可以在onReceive中调用unregisterReceiver和stopSelf。
PD2:如果服务正常完成或者您的IntentReceiver泄露错误,请不要忘记调用unregisterReceiver。
答案 3 :(得分:2)
在 IntentService 的情况下,在onHandleIntent
方法完成上一个请求之前,它不会停止或通过某些意图操作接受任何其他请求。
如果我们尝试再次使用其他操作启动 IntentService ,则仅在先前的意图/任务完成时才会调用onHandleIntent
。
在stopService(intent);
方法完成任务之前,stopSelf();
或onHandleIntent()
也不起作用。
所以我认为更好的解决方案是在这里使用普通的Service
。
我希望它会有所帮助!
答案 4 :(得分:1)
如果使用IntentService
,那么我认为你很难做到像你描述的那样,onHandleIntent()
代码必须轮询其“停止”信号。
如果您的后台任务可能长时间运行,并且您需要能够停止它,我认为您最好使用普通Service
。在较高级别,请将您的服务写入:
AsyncTask.cancel(true)
,或让onDestroy()调用AsyncTask.cancel(true)
。作为取消后台工作的交换,该服务承担以下责任:
doInBackground()
必须正常处理InterruptedException和/或定期检查Thread.interrupted(),并返回“early”。stopSelf()
(可能在AsyncTask onPostExecute / onCancelled中)。答案 5 :(得分:0)
@Override
protected void onHandleIntent(Intent intent) {
String action = intent.getAction();
if (action.equals(Action_CANCEL)) {
stopSelf();
} else if (action.equals(Action_START)) {
//handle
}
}
希望它有效。
答案 6 :(得分:0)
正如@budius在评论中已经提到的那样,当你点击那个按钮时,你应该在Service
上设置一个布尔值:
// your Activity.java
public boolean onClick() {
//...
mService.performTasks = false;
mService.stopSelf();
}
在你的Intent
处理中,在你完成提交/发送意图信息的重要任务之前,只需使用该布尔值:
// your Service.java
public boolean performTasks = true;
protected void onHandleIntent(Intent intent) {
Bundle intentInfo = intent.getBundle();
if (this.performTasks) {
// Then handle the intent...
}
}
否则,服务将执行处理Intent
的任务。这就是它的用途,
because I can't quite see how you could solve it otherwise如果查看核心代码。
答案 7 :(得分:-1)
以下是一些启动/停止服务的示例代码
首先,
Intent GPSService = new Intent(context, TrackGPS.class);
context.startService(GPSService);
停止,
context.stopService(GPSService);
答案 8 :(得分:-1)
context.stopService(GPSService);