Как долго длятся рабочие потоки Android?

Я видел несколько сообщений на эту тему, но ни в одном из них нет удовлетворительного ответа.

Предположим, что я запускаю рабочий поток из своего основного (единственного и единственного) Activity в его методе onCreate(). Затем я вызываю finish(), чтобы завершить Activity.

В этот момент задача, которой она принадлежит, уничтожается (поскольку в ней больше нет Activity). Однако приложение (и процесс, который его запускает) может продолжать существовать в пустой «каркасной» форме, так что при желании его можно быстро перезапустить (хотя оно будет очень восприимчиво к уничтожению системой).

Предполагая, что вышесказанное верно - когда рабочий поток убит? Убивается ли он только тогда, когда система активно уничтожает процесс?

В моем случае мой рабочий поток существует как прослушиватель соединения Bluetooth; при получении он снова запустит желаемый Activity. В этой ситуации нет активного работающего компонента (Activity, Service, ContentProvider или BroadcastReceiver). Мне кажется, что это должно работать, за исключением того, что что-то убивает мой рабочий поток.

Я знаю, что мог бы сделать это (и с меньшей болью), используя фон Service. Однако мне любопытно, почему это не работает.

Спасибо, Барри


person Barry Holroyd    schedule 31.12.2016    source источник
comment
Я считаю, что поток будет автоматически уничтожен только тогда, когда процесс Linux будет уничтожен.   -  person Enzokie    schedule 31.12.2016
comment
Мне кажется, что это должно работать, за исключением того, что что-то убивает мой рабочий поток Это может означать только система завершила процесс приложения. Он уничтожается только тогда, когда система активно уничтожает процесс? Правильно (или если возвращается метод run()).   -  person Onik    schedule 31.12.2016
comment
Согласовано. Тогда возникает вопрос, когда процесс убивается? Я предполагаю, что он уничтожается, когда больше нет запущенных компонентов, но я нигде не видел, чтобы это было явно задокументировано. Подробнее в моем ответе Олега на ответ BroadcastReceiver ниже.   -  person Barry Holroyd    schedule 01.01.2017


Ответы (4)


Жизненный цикл приложения Android содержит хороший пример, который очень актуален. :

Типичным примером ошибки жизненного цикла процесса является BroadcastReceiver, который запускает поток, когда получает Intent в своем методе BroadcastReceiver.onReceive(), а затем возвращается из функции. Как только он возвращается, система считает, что BroadcastReceiver больше не активен, и, следовательно, его хост-процесс больше не нужен (если в нем не активны другие компоненты приложения). Таким образом, система может завершить процесс в любое время, чтобы освободить память, и при этом она завершает порожденный поток, работающий в процессе.

Короче говоря, это действительно не очень предсказуемо, если у вашего потока будет возможность работать до завершения или процесса, который будет убит заранее, вам НЕ следует определенно полагаться на какой-либо порядок/поведение.

Отдельно стоит упомянуть, что довольно легко слить ваши активность вместе с потоком, даже если вы закончите() ее, но если это ваша последняя/единственная активность, она не меняет картину

person Oleg Bogdanov    schedule 31.12.2016
comment
Он пропускает Activity только в том случае, если Activity имеет ссылку на него. Если его поток никоим образом не ссылается на действие и является либо статическим внутренним классом, либо не внутренним классом, утечки действия не происходит, а только ссылки, которые содержит класс потока. - person Gabe Sechan; 31.12.2016
comment
ему не нужна явная ссылка, достаточно сказать new Thread() {...} в onCreate, чтобы получить неявную ссылку и бум - person Oleg Bogdanov; 31.12.2016
comment
Нет, это не так. Это верно только в том случае, если Thread не является статическим внутренним классом. Каков ваш пример (это нестатический анонимный внутренний класс), но это не обязательно. Статические внутренние классы не имеют ссылки на родительский класс. - person Gabe Sechan; 31.12.2016
comment
Учитывая, что автор не показал никакого кода о многопоточности, я явно говорил о своем примере, поэтому я не могу понять, какая часть «Нет, это не так», извините - person Oleg Bogdanov; 31.12.2016
comment
@BarryHolroyd рад помочь - person Oleg Bogdanov; 01.01.2017
comment
@Олег -- спасибо за ваши комментарии. Я думаю, что вы указали на проблему с помощью этой цитаты: как только он возвращается, система считает, что BroadcastReceiver больше не активен, и, следовательно, его хост-процесс больше не нужен. Это подразумевает (хотя все еще не указывает явно), что процесс может быть остановлен, когда в нем нет активных компонентов. Я считаю, что он все еще может существовать как пустой процесс (developer.android.com /guide/components/), и тогда поток все еще будет существовать, но его можно будет убить в любой момент. Правильный? - person Barry Holroyd; 01.01.2017
comment
Правильно, никаких гарантий как таковых - person Oleg Bogdanov; 01.01.2017
comment
Я отметил этот ответ как правильный. Резюме: рабочие потоки не прерываются системой Android. Они будут жить до: 1) завершения run() или 2) завершения процесса приложения. Процесс приложения может быть уничтожен, когда в нем больше нет запущенных компонентов, поэтому если оставить только работающий рабочий поток, он (и процесс в целом) может быть быстро уничтожен. Когда процесс может быть убит, это более широкая тема, чем обсуждаемая здесь. - person Barry Holroyd; 22.01.2017

когда рабочий поток убит? Убивается ли он только тогда, когда система активно уничтожает процесс?

-> рабочий поток считается квалифицированным после выполнения всего его кода в run функции. Он все еще работает, даже когда ваш activity уничтожен.

В моем случае мой рабочий поток существует как прослушиватель соединения Bluetooth; при получении он снова запустит желаемую активность. В этой ситуации нет активно работающего компонента (Activity, Service, ContentProvider или BroadcastReceiver). Мне кажется, что это должно работать, за исключением того, что что-то убивает мой рабочий поток.

Чтобы это работало, вам нужно иметь фон service в этом случае и сделать soft/weak ссылку на ваш service из вашего рабочего потока или проще, используя EventBus для запуска любого компонента из вашего Service как:

 EventBus.getDefault().post(new BlueToothEvent()); // call in your worker thread
// do something in your service
onBlueToothEventFired(BlueToothEvent  e);
person Kingfisher Phuoc    schedule 31.12.2016

Когда вы запускаете поток, он не зависит от родителя, который его запустил. В вашем случае это активность вашего приложения. Это означает, что пока метод Run не будет полностью выполнен, ваш поток будет жить.

Если вы выйдете из приложения (и, следовательно, вызовете метод onStop действия), поток все еще будет существовать, и вы вызовете утечку памяти. В конечном итоге он будет убит системой, если у вас закончится память.

Поскольку вы упомянули, что создали прослушиватель для прослушивания соединения Bluetooth, ваш поток, вероятно, умрет до того, как получит какое-либо событие (я не могу знать об этом без фрагмента кода). Это также может привести к сбою, что приведет к завершению потока.

person Samuel Yvon    schedule 31.12.2016
comment
Утечка памяти происходит только тогда, когда поток содержит ссылку на действие. - person Enzokie; 31.12.2016
comment
Поток может содержать ссылки на вещи, отличные от активности, что может привести к утечке указанной ссылки. - person Samuel Yvon; 31.12.2016
comment
Уточнение: я хочу, чтобы рабочий поток продолжал существовать, и я стараюсь не генерировать новые потоки после его создания. Концептуально, по крайней мере, это позволило бы ему принимать входящие запросы Bluetooth и запускать соответствующую активность, когда это происходит. Таким образом, утечки памяти не будет (пока я тщательно кодирую рабочий поток) — только память, которую я намереваюсь сохранить для целей рабочего потока. - person Barry Holroyd; 01.01.2017
comment
Как выясняется, я этого не делаю (согласно моему исходному сообщению). Когда я вызываю finish() в onCreate() из моей единственной Activity (и возвращаюсь из onCreate()), в процессе больше нет запущенных компонентов, и он становится предметом очистки системы; вскоре после этого процесс завершается, и рабочий поток вместе со всем остальным исчезает. Напротив, если бы я создал Службу и использовал ее для создания рабочего потока, Служба продолжала бы работать как компонент процесса, и вероятность того, что процесс будет уничтожен, была бы гораздо меньше (как я думаю, вы уже знаете :-) ). - person Barry Holroyd; 01.01.2017
comment
Можете ли вы опубликовать код метода запуска вашего потока? Что-то мне не хватает. Служба может не делать то, что вы ожидаете - person Samuel Yvon; 01.01.2017
comment
Извините... Я удаляю код. Однако это было не так уж много — просто запустил рабочий поток в onCreate() и через журнал увидел, что его убивают. Моя проблема на данный момент решена (мне было в основном любопытно - я не собираюсь продвигаться дальше в этом вопросе, по крайней мере, на данный момент). Спасибо за вашу помощь! - person Barry Holroyd; 03.01.2017

В Android есть один основной поток (также называемый пользовательским интерфейсом). Это единственный поток, который использует ваше приложение, если только оно не запускает его явно через Thread.start(), AsyncTask.execute() и т. д. Все действия, службы, BroadcastReceivers и т. д. запускают все свои методы жизненного цикла в этом основном потоке. Обратите внимание, что я включил Службы. Служба работает в основном потоке, если только она не запускает свой собственный поток (исключением является IntentService, который работает в своем собственном потоке).

Созданный вами Thread продолжается до тех пор, пока переданный ему Runnable не вернется из своей функции запуска (или, конечно, процесс не будет завершен). Это может жить после конца Activity/Service, которым оно было создано. Однако такой поток по-прежнему будет жить в исходном экземпляре компонента и не сможет получить доступ к переменным нового экземпляра, если он был перезапущен без особой работы (см. Шаблон загрузчика).

person Gabe Sechan    schedule 31.12.2016
comment
где автор упомянул что-либо, что противоречит вашему утверждению? он только что создал поток из onCreate - person Oleg Bogdanov; 31.12.2016
comment
@OlegBogdanov Сначала я неправильно понял его вопрос, так как думал, что onCreate запустил ветку. Я удалил часть Ты ошибаешься. - person Gabe Sechan; 31.12.2016