Страница 1 из 1

Урок 93. Service. Передача данных в сервис. Методы остановки сервиса

Добавлено: 04 июл 2012, 23:00
damager82
В этом уроке:
- передаем данные в сервис
- рассматриваем методы остановки сервиса stopSelf и stopSelfResult


Click here to read this article!

Re: Урок 93. Service. Передача данных в сервис. Методы остан

Добавлено: 29 окт 2012, 23:25
brucemax
Несмотря на обилие нового материла (чего стоит только экзэкутер), всё классно объяснено. Делаю сейчас приложение, основным элементом которого будет сервис, который запускается из главного активити и через заданный (опять же в активити) интервал спрашивает координаты у геолокационного сервиса и отсылает их гет-запросом на сервер (естественно не в потоке активити). Наверное неделю уже курю тему Сервисы на разных сайтах и никак не могу определиться по некоторым вопросам ( где лучше создавать слушатель координат, с помощью чего удобнее и рациональнее общаться с сервисом (хэндлы,биндинг или AIDL )?) Вы не наставите на путь истинный? Или возможно я поспешил и после следующих уроков мне всё станет ясно.. тогда прошу простить за нетерпение.

Re: Урок 93. Service. Передача данных в сервис. Методы остан

Добавлено: 29 окт 2012, 23:55
rezak90
на мой взгляд проще и удобней общаться при помощи AIDL, давно с ним не работал, но в проектах активно его используем.

Re: Урок 93. Service. Передача данных в сервис. Методы остан

Добавлено: 30 окт 2012, 19:59
brucemax
rezak90 писал(а):на мой взгляд проще и удобней общаться при помощи AIDL, давно с ним не работал, но в проектах активно его используем.
Спасибо! Интересно в уроках он есть..? Ладно так или иначе буду уроки смотреть здесь.

Re: Урок 93. Service. Передача данных в сервис. Методы остан

Добавлено: 31 окт 2012, 09:45
damager82
brucemax писал(а):
rezak90 писал(а):на мой взгляд проще и удобней общаться при помощи AIDL, давно с ним не работал, но в проектах активно его используем.
Спасибо! Интересно в уроках он есть..? Ладно так или иначе буду уроки смотреть здесь.
Не, в уроках только локальный биндинг. AIDL чуть сложнее,но смысл тот же.

Re: Урок 93. Service. Передача данных в сервис. Методы остан

Добавлено: 02 дек 2012, 12:04
dubok79
Уроки все прочитал по сервисам, но пишу тут, потому что тут раскрывается моя проблема.
А все-таки как решать задачу, когда последний сервис сработав раньше первого более долгоиграющего убьет сервис и что делать? Никак не могу понять.

Если я в сервисе стартую таймер на разовое выполнение, мне сервис нужно убивать сразу (он по сути мне не нужен более) или после срабатывания таймера? Спасибо

Re: Урок 93. Service. Передача данных в сервис. Методы остан

Добавлено: 03 дек 2012, 09:37
brucemax
dubok79 писал(а):Уроки все прочитал по сервисам, но пишу тут, потому что тут раскрывается моя проблема.
А все-таки как решать задачу, когда последний сервис сработав раньше первого более долгоиграющего убьет сервис и что делать? Никак не могу понять.
Использовать binding.
Если я в сервисе стартую таймер на разовое выполнение, мне сервис нужно убивать сразу (он по сути мне не нужен более) или после срабатывания таймера? Спасибо
Первое что приходит, что лучше оставить до завершения таймера, ибо это будет гарантом, что система ничего не удалит.. Но я могу ошибаться.

Re: Урок 93. Service. Передача данных в сервис. Методы остан

Добавлено: 30 мар 2013, 20:16
kondra007
Друзья! Не убивается уведомление =( Ставил везде, где мог stopService(...) - не работает.
Смотрите код, пожалуйста.

public class MyService extends Service {
NotificationManager nm;
ExecutorService es;

final String TAG = "ServiceLog";

public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate");
nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
es = Executors.newFixedThreadPool(1);
}

public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand");
Log.d(TAG, "startID = " + startId);
srv s = new srv(startId);
es.execute(s);
new Thread(s).start();
sendNotif();

return START_STICKY;
}
@Override
public IBinder onBind(Intent arg0) {
return null;
}


public void onDestroy() {
super.onDestroy();
// stopSelf();
stopService(new Intent(this, MyService.class));
Log.d(TAG, "onDestroy");
}


@SuppressLint("NewApi")
void sendNotif() {

Intent in = new Intent(this, MainActivity.class);
PendingIntent pin = PendingIntent.getActivity(this, 0, in, 0);
Notification notif = new Notification.Builder(this)
.setContentTitle("Программа запущена")
.setContentText("Нажмите, чтобы открыть приложение")
.setSmallIcon(R.drawable.ic_launcher)
.addAction(0, "Открыть приложение", pin)
.build();


// ставим флаг, чтобы уведомление пропало после нажатия
notif.flags |= Notification.FLAG_ONGOING_EVENT;

// отправляем
nm.notify(1, notif);
}


public class srv implements Runnable {
final String TAG = "SrvLog";
int startID;

public srv(int startID){
this.startID = startID;
}

public void run() {
Log.d(TAG, "Service started with id = " + startID);
stop();
}

public void stop() {
stopSelf(startID);

}
}
}

Re: Урок 93. Service. Передача данных в сервис. Методы остан

Добавлено: 09 июл 2013, 14:03
JaguaR
Привет всем!

Есть Service, в onStartCommand возвращаю START_REDELIVER_INTENT для восстановления незавершенных вызовов, сохраняя Intent. В onStartCommand создаю новый поток и запихиваю его в пул ExecutorService для поочередного выполнения (executor = Executors.newFixedThreadPool(1)), сохраняя startId в классе потока. По завершению работы потока (в run()) вызываю stopSelfResult(startId). Поток знает свой startId.

Из Activity делаю 2 вызова запуска сервиса, соответственно в сервисе 2 раза срабатывает onStartCommand и создает 2 потока с startId 1 и 2. По завершению первого потока (startId = 1) stopselfResult = false, по завершению второго потока stopselfResult = true, т.к. startId=2 является последним вызовом и сервис останавливается. Все ок.

Проблема в следующем :
Ничего не меняю в вызовах. Специально убиваю приложение сразу после получения двух вызовов onStartCommand и запуска первого потока (startId = 1). Жду когда сервис восстановится и восстановит незавершенные вызовы.. так и происходит.. Сервис создается (onCreate()), 2 раза срабатывает onStartCommand (на входе имею startId = 1 и startId = 2 и восстановленные Intent-ы), создаются потоки и отсылаются на выполнение в ExecutorService. По завершению первого потока (startId = 1) stopselfResult = false, по завершению второго потока (startId = 2)... внимание... stopselfResult = false... и соответственно сервис НЕ ОСТАНАВЛИВАЕТСЯ.. Как так?? Сервис останавливает только принудительный вызов stopselfResult(3).... Но откуда взялся третий вызов onStartCommand ? StartId были только 1 и 2.

Друзья, подскажите, почему так происходит..

Re: Урок 93. Service. Передача данных в сервис. Методы остан

Добавлено: 06 ноя 2013, 14:56
Isaev
Т.е. мы в данном примере не имеем никакой возможности "сказать" чтобы при вызове второго stopSelf сервис не убивался?
Почему нельзя проверять счётчик и отменять stop?

Re: Урок 93. Service. Передача данных в сервис. Методы остан

Добавлено: 05 дек 2013, 19:21
trew
Поэкспериментировал с кодом, сделал чтобы сервис не убивался.
[syntax=java]import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;

public class MyService extends Service {

final String TAG = "mylog";
ExecutorService es;
Object someRes;
ArrayList<Integer> userPool;
ArrayList<Integer> userPoolFinish;

public void onCreate() {
super.onCreate();
Log.d(TAG, "MyService onCreate");
es = Executors.newFixedThreadPool(3);
someRes = new Object();

userPool = new ArrayList<Integer>();
userPoolFinish = new ArrayList<Integer>();
}

public void onDestroy() {
super.onDestroy();
Log.d(TAG, "MyService onDestroy");
someRes = null;
}

public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "MyService onStartCommand");

userPool.add(startId);

int time = intent.getIntExtra("time", 1);
MyRun mr = new MyRun(time, startId);
es.execute(mr);
return super.onStartCommand(intent, flags, startId);
}

public IBinder onBind(Intent arg0) {
return null;
}

class MyRun implements Runnable {

int time;
int startId;

public MyRun(int time, int startId) {
this.time = time;
this.startId = startId;
Log.d(TAG, "MyRun#" + startId + " create");
}

public void run() {
Log.d(TAG, "MyRun#" + startId + " start, time = " + time);
try {
TimeUnit.SECONDS.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
Log.d(TAG,
"MyRun#" + startId + " someRes = " + someRes.getClass());
} catch (NullPointerException e) {
Log.d(TAG, "MyRun#" + startId + " error, null pointer");
}
stop();
}

void stop() {
//Log.d(TAG, "MyRun#" + startId + " end, stopSelfResult("
// + startId + ") = " + stopSelfResult(startId));

userPoolFinish.add(startId);
Log.d(TAG, "startId= " + startId);

if (userPool.size() == userPoolFinish.size())
{
for (int i = 0 ; i < userPool.size(); i++) {

Log.d(TAG, "userPool.get(i): " + userPool.get(i));
Log.d(TAG, "MyRun#" + userPool.get(i) + " end, stopSelf(" + userPool.get(i)
+ ")");

stopSelf(userPool.get(i));

Log.d(TAG, "MyRun ------ " + userPool.get(i) + " end, stopSelfResult("
+ userPool.get(i) + ") = " + stopSelfResult(userPool.get(i)));
}

Log.d(TAG, "stopSelfResult(1) = " + stopSelfResult(1));
Log.d(TAG, "stopSelfResult(2) = " + stopSelfResult(2));
Log.d(TAG, "stopSelfResult(3) = " + stopSelfResult(3));
}
}
}
}[/syntax]

Лог
[syntax=xml]12-05 16:09:07.721: D/mylog(985): MyService onCreate
12-05 16:09:07.730: D/mylog(985): MyService onStartCommand
12-05 16:09:07.730: D/mylog(985): MyRun#1 create
12-05 16:09:07.741: D/mylog(985): MyService onStartCommand
12-05 16:09:07.741: D/mylog(985): MyRun#2 create
12-05 16:09:07.741: D/mylog(985): MyRun#1 start, time = 7
12-05 16:09:07.741: D/mylog(985): MyService onStartCommand
12-05 16:09:07.752: D/mylog(985): MyRun#3 create
12-05 16:09:07.752: D/mylog(985): MyRun#2 start, time = 2
12-05 16:09:07.761: D/mylog(985): MyRun#3 start, time = 4
12-05 16:09:09.784: D/mylog(985): MyRun#2 someRes = class java.lang.Object
12-05 16:09:09.784: D/mylog(985): startId= 2
12-05 16:09:11.791: D/mylog(985): MyRun#3 someRes = class java.lang.Object
12-05 16:09:11.791: D/mylog(985): startId= 3
12-05 16:09:14.766: D/mylog(985): MyRun#1 someRes = class java.lang.Object
12-05 16:09:14.766: D/mylog(985): startId= 1
12-05 16:09:14.766: D/mylog(985): userPool.get(i): 1
12-05 16:09:14.766: D/mylog(985): MyRun#1 end, stopSelf(1)
12-05 16:09:14.784: D/mylog(985): MyRun ------ 1 end, stopSelfResult(1) = false
12-05 16:09:14.784: D/mylog(985): userPool.get(i): 2
12-05 16:09:14.784: D/mylog(985): MyRun#2 end, stopSelf(2)
12-05 16:09:14.784: D/mylog(985): MyRun ------ 2 end, stopSelfResult(2) = false
12-05 16:09:14.791: D/mylog(985): userPool.get(i): 3
12-05 16:09:14.791: D/mylog(985): MyRun#3 end, stopSelf(3)
12-05 16:09:14.791: D/mylog(985): MyService onDestroy
12-05 16:09:14.801: D/mylog(985): MyRun ------ 3 end, stopSelfResult(3) = false
12-05 16:09:14.801: D/mylog(985): stopSelfResult(1) = false
12-05 16:09:14.801: D/mylog(985): stopSelfResult(2) = false
12-05 16:09:14.801: D/mylog(985): stopSelfResult(3) = false[/syntax]
Видим, что stopSelfResult() вернул false, для всех потоков.
Кто остановил сервис?

Re: Урок 93. Service. Передача данных в сервис. Методы остан

Добавлено: 30 май 2014, 17:42
kot_droid
штука смотрю совершенно не предсказуемая, вот еще пример:)
создаю сервис и запускаю на 30 секунд, во время работы делаю stopService - сервис продолжает работать.
закрываю активити - сервис работает, но даже после того как отработал не уничтожился.
опять открываю активити, запускаю сервис, делаю stopService и выхожу из активити
сервис как и в прошлый рас работает
запускаю опять активити, запускаю сервис и у меня уже 2 сервиса спамят лог:)
в общем успешно уничтожился, только когда дождался как он отработает и после этого сделал stopService

Re: Урок 93. Service. Передача данных в сервис. Методы остан

Добавлено: 21 июл 2014, 12:51
Stormer
Это как в Java, если запустить поток с while(true), то interrupt его ни фига не прервет. Кстати, кто знает, как остановить такой поток?

Простите за тупую аналогию))

Re: Урок 93. Service. Передача данных в сервис. Методы остан

Добавлено: 21 июл 2014, 19:51
Mikhail_dev
interrupt - это флаг потоку, который надо проверять и думать, когда остановить поток. Раньше был stop, но останавливать в произвольный момент времени поток не есть хорошо, поэтому придумали этот флаг. Каждый раз при начале цикла, либо логической цепочки, можно проверять данный флаг.
Еще как вариант, бросать return false внутри цикла и выходить с него.
еще как вариант, если используется Thread.sleep, то тот де вроде interrupt, Либо join (не помню). Тогда вылетет исключение и поток завершится. То, что вылетет исключение - это нормально в данном случае.

Re: Урок 93. Service. Передача данных в сервис. Методы остан

Добавлено: 21 июл 2014, 19:53
Mikhail_dev
штука смотрю совершенно не предсказуемая, вот еще пример:)
создаю сервис и запускаю на 30 секунд, во время работы делаю stopService - сервис продолжает работать.
закрываю активити - сервис работает, но даже после того как отработал не уничтожился.
опять открываю активити, запускаю сервис, делаю stopService и выхожу из активити
сервис как и в прошлый рас работает
запускаю опять активити, запускаю сервис и у меня уже 2 сервиса спамят лог:)
в общем успешно уничтожился, только когда дождался как он отработает и после этого сделал stopService
У вас утечка. Почитайте данную статью - http://habrahabr.ru/post/222199/

Re: Урок 93. Service. Передача данных в сервис. Методы остан

Добавлено: 28 янв 2015, 16:58
Nialon
Стало любопытно. Идея с вводом счетчика для отлова потоков правильная,
только мне не нужен НЕ убиваемый сервис как у пользователя выше.
Вот мой вариант кода полностью годный для примера. Там много тэгов для разностороннего учета.

Код: Выделить всё

public class MyService extends Service {

    final String TAG = "mylog";
    ExecutorService es;
    Object someRes;
    int EndId = 0;
    int WorkCount = 0;
    Boolean OnStop = false;

    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "MyService onCreate");
        es = Executors.newFixedThreadPool(3);
        someRes = new Object();
    }

    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "MyService onDestroy");
        OnStop = true;
        someRes = null;
    }

    public int onStartCommand(Intent intent, int flags, int startId) {

        EndId++;
        WorkCount += startId;
        Log.d(TAG, "MyService onStartCommand");
        int time = intent.getIntExtra("time", 1);
        MyRun mr = new MyRun(time, startId);
        es.execute(mr);
        return super.onStartCommand(intent, flags, startId);
    }

    public IBinder onBind(Intent arg0) {
        return null;
    }

    class MyRun implements Runnable {

        int time;
        int startId;

        public MyRun(int time, int startId) {
            this.time = time;
            this.startId = startId;
            Log.d(TAG, "MyRun#" + startId + " create");
        }

        public void run() {

            if (OnStop) {
                Log.d(TAG, "MyRun#" + startId + " start, service destroyed, Exit.");
                return;
            }

            Log.d(TAG, "MyRun#" + startId + " start, time = " + time);

            try { TimeUnit.SECONDS.sleep(time); }
            catch (InterruptedException e) { e.printStackTrace(); }

            if (OnStop) {
                Log.d(TAG, "MyRun#" + startId + " after SLEEP, service destroyed, Exit.");
                return;
            }

            try {Log.d(TAG,"MyRun#" + startId + " someRes = " + someRes.getClass());
            } catch (NullPointerException e) { Log.d(TAG, "MyRun#" + startId + " error, null pointer"); }

            stop();
        }

        void stop() {

            if (OnStop) {
                Log.d(TAG, "MyRun#" + startId + " end, + service destroyed..");
            } else
            if (WorkCount == startId) {
                Log.d(TAG, "MyRun#" + startId + " last end, stopSelfResult("+ EndId + ") = " + stopSelfResult(EndId));
            } else {
                WorkCount -= startId;
                Log.d(TAG, "MyRun#" + startId + " end, Wait for stop previus");
            }
        }

    }
}
Самое забавное если не занулять объект в блоке уничтожения сервиса, он доступен после. Как-то неправильно...

Re: Урок 93. Service. Передача данных в сервис. Методы остан

Добавлено: 21 сен 2015, 16:52
Kirill
Nialon писал(а): int WorkCount = 0;

WorkCount += startId;
1. странно видеть имена переменных с большой буквы
2. WorkCount увеличивается не на +1, а на значение startId, то есть +1 +2 +3, выглядит подозрительно

Re: Урок 93. Service. Передача данных в сервис. Методы остан

Добавлено: 15 дек 2017, 12:10
danek130995
К слову о том, почему автор пишет, что "Но на самом деле алгоритм чуть другой. Сервис останавливается, когда последний полученный (а не последний обработанный) вызов выполняет метод stopSelf(startId). А при этом могут продолжать работать ранее полученные вызовы. Почему так сделано – я не знаю."

Согласно официальным докам(https://developer.android.com/guide/com ... l#Stopping),
"If your service handles multiple requests to onStartCommand() concurrently, you shouldn't stop the service when you're done processing a start request, as you might have received a new start request (stopping at the end of the first request would terminate the second one). To avoid this problem, you can use stopSelf(int) to ensure that your request to stop the service is always based on the most recent start request. That is, when you call stopSelf(int), you pass the ID of the start request (the startId delivered to onStartCommand()) to which your stop request corresponds. Then, if the service receives a new start request before you are able to call stopSelf(int), the ID does not match and the service does not stop."

"Если ваш сервис обрабатывает множество запросов одновременно (onStartCommand()), вам не следует останавливать сервис, когда завершилась обработка запроса, так как сервис может принять новый запрос (остановка сервиса в конце первого запроса завершит и второй). Чтобы избежать этого, можно использовать stopSelf(int) чтобы удостовериться, что ваш запрос на остановку сервиса всегда базируется на самом последнем запросе старта. Поэтому, когда вы вызываете метод stopSelf(int), вы передаете id запроса старта(которое потом попадает в onStartCommand(), к которому относится ваш запрос на остановку. Тогда, если сервис получит новый запрос на старт перед тем как у вас есть возможность вызвать stopSelft(int), ID не совпадет и сервис не остановится)."
Надеюсь, кому-то помог.

Re: Урок 93. Service. Передача данных в сервис. Методы остановки сервиса

Добавлено: 11 сен 2021, 11:49
Rolik
Не смог заменит логи на тосты и вывести в UI, жаль...