如何使用Activity中的取消按钮强制IntentService立即停止?

时间:2012-06-29 07:54:16

标签: android intentservice

我有一个从Activity启动的IntentService,我希望能够通过活动中的“取消”按钮立即停止活动。一旦按下“取消”按钮,我希望服务停止执行代码行。

我发现了许多类似的问题(例如herehereherehere),但没有好的答案。 Activity.stopService()Service.stopSelf()立即执行Service.onDestroy()方法,但在销毁服务之前让onHandleIntent()中的代码完成。

由于显然没有保证立即终止服务线程的方法,我能找到的唯一推荐的解决方案(here)是在服务中有一个布尔成员变量,可以在{{1方法,然后几乎在onDestroy()中的每一行代码都包含在自己的“if”子句中查看该变量。这是编写代码的一种糟糕方式。

有人知道在IntentService中更好的方法吗?

9 个答案:

答案 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以执行后台工作,从而节省对新创建的AsyncTask的引用。
  • 公开“取消”意图以调用AsyncTask.cancel(true),或让onDestroy()调用AsyncTask.cancel(true)
  • 然后,Activity可以发送“取消”Intent或只调用stopService()。

作为取消后台工作的交换,该服务承担以下责任:

  • AsyncTask 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);