Как заставить IntentService немедленно остановить кнопку отмены из Activity?
У меня есть IntentService, который запускается из Activity, и я хотел бы иметь возможность немедленно прекратить работу службы с помощью кнопки "cancel" в действии. Как только эта кнопка "отменить" будет нажата, я хочу, чтобы служба прекратила выполнение строк кода.
Я нашел несколько вопросов, подобных этому (т.е. здесь, здесь, здесь, здесь), но нет хороших ответов. Activity.stopService()
и Service.stopSelf()
немедленно выполните метод Service.onDestroy()
, но затем пусть код в onHandleIntent()
закончен до полного уничтожения службы.
Поскольку, по-видимому, нет гарантированного способа немедленно прекратить поток обслуживания, единственное рекомендуемое решение, которое я могу найти (здесь), должно быть логическую переменную-член в службе, которая может быть переключена в методе onDestroy()
, а затем имеет примерно каждую строку кода в onHandleIntent()
, завернутую в свое собственное предложение if if, рассматривающее эту переменную. Это ужасный способ написать код.
Знает ли кто-нибудь лучший способ сделать это в IntentService?
Ответы
Ответ 1
Остановка потока или процесса немедленно часто является грязной вещью. Тем не менее, это должно быть хорошо, если ваш сервис является апатридом.
Объявить службу как отдельный процесс в манифесте:
<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
Вот трюк, используйте изменчивую статическую переменную и проверьте условие продолжения в некоторых строках вашей службы, которые должны быть проверены службой:
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;
Ответ 3
Я использовал BroadcastReceiver внутри службы, который просто ставит логическое значение stop в 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: Я использую логическое значение, потому что в моем случае я останавливаю службу, находясь в цикле, но вы, вероятно, можете вызвать unregisterReceiver и stopSelf в onReceive.
PD2: не забудьте вызвать unregisterReceiver, если служба завершила его работу нормально или вы получите пропущенную ошибку IntentReceiver.
Ответ 4
В случае IntentService он не останавливается или не принимает какой-либо другой запрос через какое-либо действие до тех пор, пока его метод onHandleIntent
не завершит предыдущий запрос.
Если мы снова попытаемся запустить IntentService с помощью другого действия, onHandleIntent
будет вызываться только после завершения предыдущего намерения/задачи.
Также stopService(intent);
или stopSelf();
не работает, пока метод onHandleIntent()
не завершит свою задачу.
Итак, я думаю, что здесь лучше использовать обычный Service
здесь.
Надеюсь, это поможет!
Ответ 5
Если вы используете IntentService
, то я думаю, что вы застряли над тем, что вы описываете, где код onHandleIntent()
должен опросить его сигнал "stop".
Если фоновая задача потенциально длительная, и если вам нужно ее остановить, я думаю, что вам лучше использовать простой Service
. На высоком уровне напишите свой Сервис:
- Представьте "начало" намерения запустить AsyncTask для выполнения фоновой работы, сохранив ссылку на эту недавно созданную AsyncTask.
- Выставить намерение "отменить" для вызова
AsyncTask.cancel(true)
или включить onDestroy() invoke AsyncTask.cancel(true)
.
- Затем действие может либо отправить намерение "отменить", либо просто вызвать stopService().
В обмен на возможность отмены фоновой работы Служба берет на себя следующие обязанности:
- AsyncTask
doInBackground()
должен будет изящно обрабатывать InterruptedException и/или периодически проверять Thread.interrupted() и возвращать "раньше".
- Служба должна гарантировать, что вызывается
stopSelf()
(возможно, в AsyncTask onPostExecute/onCancelled).
Ответ 6
@Override
protected void onHandleIntent(Intent intent) {
String action = intent.getAction();
if (action.equals(Action_CANCEL)) {
stopSelf();
} else if (action.equals(Action_START)) {
//handle
}
}
Надеюсь, что это сработает.
Ответ 7
Как уже упоминалось в его комментарии @budius, вы должны установить boolean на 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
. То, как оно предназначалось для использования,
потому что я не могу понять, как вы могли бы его решить иначе, если вы посмотрите на основной код.
Ответ 8
Вот пример кода для запуска/остановки службы
Чтобы начать,
Intent GPSService = new Intent(context, TrackGPS.class);
context.startService(GPSService);
Чтобы остановить,
context.stopService(GPSService);
Ответ 9
context.stopService(GPSService);