Запуск службы из другой службы и передача по значению

У меня есть служба в моем приложении для Android. Во время onStartCommand я передаю объект службы другому классу. Затем оттуда появляется поток, который через 30 секунд запускает другую службу. Это что-то вроде этого:

public class FooService extends Service {

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

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        MyClass mc = new MyClass(this);
        mc.testMethod();
        stopSelf();
        return START_NOT_STICKY;
    }
}

А это MyClass:

public class MyClass {

    private Service service;

    public MyClass(Service service) {
        this.service = service;
    }

    public void testMethod() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(20*1000);
                    Intent intent = new Intent(service, BarService.class);
                    service.startService(intent);
                }
                catch (Exception e) {
                    // CATCH!
                }
            }
        }).start();
    }
}

Теперь, как видите, в FooService я вызываю функцию stopSelf(), которая уничтожает этот объект службы. Кстати, у MyClass есть копия этой службы, которая была передана по значению. Через 20 секунд мы можем запустить BarService из MyClass. Я проверил это, и это работает, но я не могу понять, почему! То, как я написал код, грязно (для меня). Правильно ли запускать другую службу из уничтоженной? Спасибо за помощь.


person Angelo    schedule 12.03.2014    source источник
comment
Справочное ведение. Просто нормально. Для этого следует использовать AlarmManager.   -  person shemsu    schedule 12.03.2014
comment
@SoothSayer Это не ссылка (или указатель, или что-то еще). Java передается по значению, это означает, что сам объект уничтожен, но у меня есть копия этой службы, даже если она не запущена. Это теоретическая проблема: правильно ли запускать другую службу из той, которую я уничтожил с помощью stopSelf()? Я реализовал AlarmManager, но прямо сейчас я каждый раз обновляю объект службы внутри MyClass.   -  person Angelo    schedule 12.03.2014
comment
Используйте Handler с Messenger и продолжайте обновлять свой сервис через активность.   -  person TheLittleNaruto    schedule 12.03.2014
comment
Java - это не передача по значению, я имею в виду, да, но это не так просто. И stopSelf() != уничтоженный объект. ИМО, запускать другую службу из остановленной службы - не очень хорошая идея. Работает, потому что ваш сервис остановлен, но все еще существует.   -  person shemsu    schedule 12.03.2014


Ответы (1)


Я проверил это, и это работает, но я не могу понять, почему

Он работает сегодня в средах, в которых вы тестировали. Он может работать не во всех средах (например, моды ПЗУ) и может не работать завтра (например, обновления ОС Android). Уничтоженный Context, такой как ваша остановленная служба, не должен использоваться ни для чего. Случается, что сейчас вы все еще можете использовать его для вызова startService() позже, но такое поведение не гарантируется.

Правильно ли запускать другую службу из уничтоженной?

Нет. В данном случае я не понимаю, зачем вообще нужны две службы.

У меня есть копия этого сервиса

Нет, ты не.

person CommonsWare    schedule 12.03.2014
comment
Итак, в этот момент я думаю, что возвращаюсь назад и путаю передачу по ссылке, передачу по значению... - person Angelo; 12.03.2014
comment
@Angelo: stackoverflow.com/questions/40480/is- java-pass-by-reference В двух словах, service в вашем конструкторе MyClass является указателем на объект Service. Этот указатель копируется (передается по значению) из исходного местоположения (this в вашем сервисе). Базовый объект не копируется. - person CommonsWare; 12.03.2014
comment
Я слишком много раз читал эту чертову ссылку :D Итак, передача по значению означает, что копируется указатель, а не сам объект. Хорошо! Итак, даже если я вызываю stopSelf() (как указано в SoothSayer), объект службы не уничтожается, у меня все еще есть ссылка в MyClass, и GC не уничтожит ее... НО она недоступна в среде Android. Он по-прежнему работает только потому, что объект находится где-то в моем стеке, верно? - person Angelo; 12.03.2014
comment
@Angelo: даже если я вызываю stopSelf() (как указано в SoothSayer), объект Service не уничтожается - да, с точки зрения использования глагола destroy в Android. onDestroy() будет вызываться в Service после stopSelf(), а объект Service больше не должен использоваться после этой точки. Я читал эту чертову ссылку слишком много раз - лично я думаю, что большинству разработчиков Java проще думать об объектах Java как о передаче по ссылке, а примитивы Java передаются по значению. - person CommonsWare; 12.03.2014
comment
@Angelo: Это все еще работает только потому, что объект находится где-то в моем стеке, верно? -- он по-прежнему работает только потому, что stopSelf() и поведение, которое оно запускает, не испортит Service настолько, чтобы заставить его не работать, когда вы вызываете на нем startService(). Однако, опять же, это может быть изменено любым, у кого есть исходный код Service, например производителями устройств, моддерами ПЗУ и самой Google. Следовательно, не полагайтесь на то, что startService() будет работать над разрушенным Service. - person CommonsWare; 12.03.2014
comment
хорошо, мы поняли друг друга, уничтожение имелось в виду как уничтожение из памяти и освобождение, а не вызов onDestroy() и т. д. ... p.s: я использую FooService и BarService, потому что они делают разные вещи в их onStartCommand()! (вы спрашивали, почему я использую два Сервиса) - person Angelo; 12.03.2014
comment
@Angelo: Ты все еще можешь быть на службе. Используйте оператор if в onStartCommand(), ветвление на основе дополнительного в Intent. - person CommonsWare; 12.03.2014
comment
Я знаю, что об этом следует спросить в другом месте, но речь идет об игре с пропуском службы ... в MyClass мне нужен контекст. Поскольку это всегда меняется, следует ли мне использовать ApplicationContext или каждый раз обновлять контекст службы в MyClass? - person Angelo; 12.03.2014
comment
@Angelo: если экземпляр MyClass используется только одним Service, используйте Service. Если экземпляр MyClass может использоваться несколькими компонентами (например, это синглтон), используйте getApplication() для извлечения Application и используйте его, чтобы избежать утечки памяти. - person CommonsWare; 12.03.2014