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

pva*_*ans 43 android intentservice

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

我发现了许多与此类似的问题(即这里,这里,这里,这里),但没有好的答案. Activity.stopService()并立即Service.stopSelf()执行该Service.onDestroy()方法,然后onHandleIntent()在销毁服务之前让代码完成.

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

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

Sad*_*egh 35

下面是技巧,使用易失性静态变量并检查服务中某些行中的继续条件,应检查服务继续:

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
   }
}
Run Code Online (Sandbox Code Playgroud)

并在您的活动中这样做是为了停止您的服务,

 MyService.shouldContinue = false;
Run Code Online (Sandbox Code Playgroud)

  • @skynet`IntentService`有自己独立的线程.更好的方法是在`shouldContinue`字段中使用`synchronized` setter和getter. (2认同)

kup*_*sef 12

立即停止线程或进程通常是一件坏事.但是,如果您的服务是无状态的,那应该没问题.

将服务声明为清单中的单独进程:

<service
     android:process=":service"
     ...
Run Code Online (Sandbox Code Playgroud)

当你想要停止它的执行时,只需杀掉那个进程:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 替换Process.killProcess(next.pid); android.os.Process.killProcess(next.pid); java Process与Android Process不同. (6认同)
  • 当然是不同的,但是您不必使用新的import-&gt;`import android.os.Process`来键入完全限定的名称。就像使用标准Java-&gt;`import java.lang.Process`。 (2认同)
  • 你永远不应该像这样终止任何并发任务。否则您可能会损坏任何更新的数据。最好的技术是通过事务块真正分离您的任务,并在进一步之前检查取消变量(如 Sirlate 代码,波纹管)。如果你不喜欢“ifs”,让你的条件代码看起来更好。但无论如何都是条件代码。:) (2认同)

Joe*_*yCK 6

我在服务中使用了一个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();
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,从活动电话:

//STOP SERVICE
Intent sIntent = new Intent();
sIntent.setAction(StopReceiver.ACTION_STOP);
sendBroadcast(sIntent);
Run Code Online (Sandbox Code Playgroud)

停止服务

PD:我使用布尔值,因为在我的情况下,我在循环中停止服务但你可以在onReceive中调用unregisterReceiver和stopSelf.

PD2:如果服务正常完成或者您将收到泄漏的IntentReceiver错误,请不要忘记调用unregisterReceiver.