• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1page.title=Процессы и потоки
2page.tags=жизненный цикл,фон
3
4@jd:body
5
6<div id="qv-wrapper">
7<div id="qv">
8
9<h2>Содержание документа</h2>
10<ol>
11<li><a href="#Processes">Процессы</a>
12  <ol>
13    <li><a href="#Lifecycle">Жизненный цикл процесса</a></li>
14  </ol>
15</li>
16<li><a href="#Threads">Потоки</a>
17  <ol>
18    <li><a href="#WorkerThreads">Рабочие потоки</a></li>
19    <li><a href="#ThreadSafe">Потокобезопасные методы</a></li>
20  </ol>
21</li>
22<li><a href="#IPC">Взаимодействие процессов</a></li>
23</ol>
24
25</div>
26</div>
27
28<p>Когда компонент приложения запускается при отсутствии других работающих компонентов
29, система Android запускает новый процесс Linux для приложения с одним потоком
30выполнения. По умолчанию все компоненты одного приложения работают в одном процессе и потоке
31(называется «главным потоком»). Если компонент приложения запускается при наличии процесса
32для этого приложения (так как существует другой компонент из приложения), тогда компонент
33запускается в этом процессе и использует тот же поток выполнения. Однако можно организовать выполнение
34других компонентов приложения в отдельных процессах и создавать дополнительный
35поток для любого процесса.</p>
36
37<p>В этом документе обсуждается работа процессов и потоков в приложении Android.</p>
38
39
40<h2 id="Processes">Процессы</h2>
41
42<p>По умолчанию все компоненты одного приложения работают в одном процессе, и большинство приложений
43не должно менять это поведение. Однако, если необходимо контролировать, к какому процессу принадлежат определенный
44компонент, можно сделать это в файле манифеста.</p>
45
46<p>Запись манифеста для каждого типа элементов компонента &mdash;<a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code
47&lt;activity&gt;}</a>, <a href="{@docRoot}guide/topics/manifest/service-element.html">{@code
48&lt;service&gt;}</a>, <a href="{@docRoot}guide/topics/manifest/receiver-element.html">{@code
49&lt;receiver&gt;}</a> и <a href="{@docRoot}guide/topics/manifest/provider-element.html">{@code
50&lt;provider&gt;}</a> &mdash;поддерживает атрибут {@code android:process}, позволяющий задавать
51процесс, в котором следует выполнять этот компонент. Можно установить этот атрибут так, чтобы каждый компонент выполнялся
52в собственном процессе, или так, чтобы только некоторые компоненты совместно использовали один процесс.  Можно также настроить процесс
53{@code android:process} так, чтобы компоненты разных приложений выполнялись в одном
54процессе, при условии что приложения совместно используют один идентификатор пользователя Linux и выполняют вход с
55одним сертификатом.</p>
56
57<p>Элемент <a href="{@docRoot}guide/topics/manifest/application-element.html">{@code
58&lt;application&gt;}</a> также поддерживает атрибут {@code android:process}, позволяющий задать
59значение по умолчанию, которое применяется ко всем компонентам.</p>
60
61<p>Android может остановить процесс в некоторой точке, когда не хватает памяти и она необходима другим
62процессам, которые обслуживают пользователя в данный момент. Работа компонентов
63приложения, работающих в этом процессе, последовательно останавливается.  Процесс для этих компонентов запускается
64повторно, когда для них появляется работа.</p>
65
66<p>Принимая решение о прерывании процессов, система Android взвешивает их относительную важность
67для пользователя.  Например, более вероятно выключение процессов, содержащих действия, которые
68не отображаются на экране, по сравнению с процессом, содержащим видимые действия. Следовательно, решение
69о прерывании процесса зависит от состояния компонентов, работающих в этом процессе. Ниже обсуждаются правила,
70на основании которых принимается решение о выборе прерываемых процессов. </p>
71
72
73<h3 id="Lifecycle">Жизненный цикл процесса</h3>
74
75<p>Система Android пытается сохранять процесс приложения как можно дольше, но
76 в конечном счете вынуждена удалять старые процессы, чтобы восстановить память для новых или более важных процессов.  Чтобы
77определить, какие процессы сохранить,
78а какие удалить, система помещает каждый процесс в «иерархию важности» на основе
79компонентов, выполняющихся в процессе, и состояния этих компонентов.  Процессы с самым низким уровнем
80важности исключаются в первую очередь, затем исключаются процессы следующего уровня важности и т. д., насколько это необходимо
81для восстановления ресурсов системы.</p>
82
83<p>В иерархии важности предусмотрено пять уровней. В следующем списке представлены различные
84типы процессов в порядке важности (первый процесс является <em>наиболее важным</em> и
85<em>удаляется в последнюю очередь</em>):</p>
86
87<ol>
88  <li><b>Процесс переднего плана</b>
89    <p>Процесс, необходимый для текущей деятельности пользователя.  Процесс
90 считается процессом переднего плана, если выполняется любое из следующих условий:</p>
91
92      <ul>
93        <li>Он содержит действие {@link android.app.Activity}, с которым взаимодействует пользователь (вызван метод {@link
94android.app.Activity}
95{@link android.app.Activity#onResume onResume()}).</li>
96
97        <li>Он содержит службу {@link android.app.Service}, связанную с действием, с которым
98взаимодействует пользователь.</li>
99
100        <li>Он содержит службу {@link android.app.Service}, которая выполняется "на переднем плане", &mdash; службу,
101которая называется {@link android.app.Service#startForeground startForeground()}.
102
103        <li>Он содержит службу{@link android.app.Service}, которая выполняет один из обратных вызовов
104 жизненного цикла ({@link android.app.Service#onCreate onCreate()}, {@link android.app.Service#onStart
105onStart()} или {@link android.app.Service#onDestroy onDestroy()}).</li>
106
107        <li>Он содержит ресивер {@link android.content.BroadcastReceiver}, который выполняет метод {@link
108android.content.BroadcastReceiver#onReceive onReceive()}.</li>
109    </ul>
110
111    <p>Обычно одновременно работает лишь несколько процессов переднего плана.  Они уничтожаются только
112в крайнем случае, если памяти остается так мало, что они не могут продолжать совместную работу.  Обычно в этот момент
113устройство достигло состояния разбиения памяти на страницы, поэтому для того, чтобы пользовательский интерфейс откликался на действия пользователя, необходимо
114удаление некоторых процессов на переднем плане.</p></li>
115
116  <li><b>Видимые процессы</b>
117    <p>Процессы, которые не содержат компонентов переднего плана, но могут
118влиять на отображение на экране. Процесс считается видимым,
119если выполняется любое из следующих условий:</p>
120
121      <ul>
122        <li>Он содержит действие {@link android.app.Activity}, которое не находится на переднем плане, но
123видно пользователю (вызван метод {@link android.app.Activity#onPause onPause()}).
124Например, это может происходить, если действие на переднем плане запустило диалоговое окно, которое позволяет видеть
125предыдущее действие позади него.</li>
126
127        <li>Он содержит службу {@link android.app.Service}, связанную с видимым
128действием или действием переднего плана.</li>
129      </ul>
130
131      <p>Видимый процесс считается исключительно важным, его следует удалять
132только в случае, если требуется сохранить работу всех процессов переднего плана. </p>
133    </li>
134
135  <li><b>Служебный процесс</b>
136    <p>Процесс, который выполняет службу, запущенную с помощью метода {@link
137android.content.Context#startService startService()}, и не попадает ни в одну из двух
138категорий более высокого уровня. Хотя служебные процессы не связаны непосредственно с тем, что видит пользователь,
139они обычно выполняют важные для пользователя действия (например, воспроизводят музыку в фоновом режиме или
140загружают данные в сеть), поэтому система сохраняет их выполнение, если памяти достаточно для
141их работы наряду со всеми видимыми процессами и процессами переднего плана. </p>
142  </li>
143
144  <li><b>Фоновый процесс</b>
145    <p>Процесс, содержащий действия, которые не видны пользователю в настоящее время (вызван метод
146{@link android.app.Activity#onStop onStop()} действия). Эти процессы не оказывают непосредственного
147воздействия на работу пользователя, и система может удалить их в любой момент, чтобы освободить память для
148процессов переднего плана,
149видимых или служебных процессов. Обычно выполняется множество фоновых процессов, поэтому они хранятся в списке
150LRU (недавно использованные), чтобы процессы, содержащие самые
151недавние действия, которые видел пользователь, удалялись в последнюю очередь. Если для действия правильно реализованы методы жизненного цикла,
152и действие сохраняет текущее состояние, удаление процесса этого действия не оказывает видимого воздействия на
153работу пользователя, так как когда пользователь возвращается к этому действию, оно восстанавливает
154все элементы своего видимого состояния. Информацию о сохранении и восстановлении состояния см. в документе <a href="{@docRoot}guide/components/activities.html#SavingActivityState">Действия</a>
155.</p>
156  </li>
157
158  <li><b>Пустой процесс</b>
159    <p>Процесс, не содержащий никаких компонентов активного приложения.  Единственная причина сохранять процесс
160такого типа — это кэширование, которое улучшает время следующего запуска
161компонента в этом процессе.  Система часто удаляет эти процессы для равномерного распределения всех системных
162ресурсов между кэшем процесса и кэшем базового ядра.</p>
163  </li>
164</ol>
165
166
167  <p>Система Android относит процесс к максимально высокому уровню на основе важности
168компонентов, активных в процессе в текущее время.  Например, если процесс содержит служебное и видимое действие,
169процесс считается видимым, а не служебным процессом.</p>
170
171  <p>Кроме того, уровень процесса может быть повышен, поскольку имеются другие процессы, зависимые от него.
172Например, процесс, обслуживающий другой процесс, не может иметь уровень ниже уровня обслуживаемого
173процесса. Например, если поставщик контента в процессе A обслуживает клиента в процессе B или
174служебный процесс A связан с компонентом в процессе B, процесс A всегда считается не менее
175важным, чем процесс B.</p>
176
177  <p>Так как процесс, выполняющий службу, оценивается выше процесса с фоновыми действиям,
178действие, запускающее долговременную операцию, может запустить <a href="{@docRoot}guide/components/services.html">службу</a> для этой операции, а не просто
179создать рабочий поток, особенно в случае, если операция продлится дольше действия.
180Например, действие, которое загружает изображение на веб-сайт, должно запустить службу для выполнения
181загрузки, так что загрузка может продолжаться в фоновом режиме даже после выхода пользователя из действия.
182Использование службы гарантирует, что операция будет иметь приоритет не ниже «служебного процесса»,
183независимо от того, что происходит с действием. По этой же причине ресиверы должны
184использовать службы, а не просто ставить в поток операции, требующие много времени для выполнения.</p>
185
186
187
188
189<h2 id="Threads">Потоки</h2>
190
191<p>При запуске приложения система создает поток выполнения для приложения,
192который называется «главным». Этот поток очень важен, так как он отвечает за диспетчеризацию событий
193на виджеты соответствующего интерфейса пользователя, включая события графического представления. Он также является потоком, в котором
194приложение взаимодействует с компонентами из набора инструментов пользовательского интерфейса Android (компонентами из пакетов {@link
195android.widget} и {@link android.view}). По существу, главный поток — это то, что иногда называют
196потоком пользовательского интерфейса.</p>
197
198<p>Система <em>не</em> создает отдельного потока для каждого экземпляра компонента. Все
199компоненты, которые выполняются в одном процессе, создают экземпляры в потоке пользовательского интерфейса, и системные вызовы
200каждого компонента отправляются из этого потока. Поэтому методы, которые отвечают на системные
201обратные вызовы (такие как метод {@link android.view.View#onKeyDown onKeyDown()} для сообщения о действиях пользователя
202или метод обратного вызова жизненного цикла), всегда выполняются в потоке пользовательского интерфейса процесса.</p>
203
204<p>Например, когда пользователь нажимает кнопку на экране, поток пользовательского интерфейса вашего приложения отправляет
205событие нажатия в виджет, который, в свою очередь, устанавливает кнопку в нажатое состояние и отправляет запрос на аннулирование
206в очередь событий. Поток пользовательского интерфейса исключает запрос из очереди и уведомляет виджет, что он должен
207отобразиться повторно.</p>
208
209<p>Когда приложение выполняет интенсивную работу в ответ на действия пользователя, эта одиночная модель потока
210может показывать плохую производительность, если приложение реализовано неправильно. То есть, если
211все происходит в потоке пользовательского интерфейса, выполнение долговременных операций, таких как сетевой доступ или
212запросы к базе данных, будет блокировать весь пользовательский интерфейс. Когда поток заблокирован, не могут обрабатываться никакие события,
213включая события изменения отображения. С точки зрения пользователя
214приложение выглядит зависшим. Хуже того, если поток пользовательского интерфейса заблокирован более нескольких секунд
215(в настоящее время около 5 секунд), отображается печально известное диалоговое окно <a href="http://developer.android.com/guide/practices/responsiveness.html">«приложение не
216отвечает</a>». После этого недовольный пользователь может выйти из вашего приложения
217и удалить его.</p>
218
219<p>Кроме того, набор инструментов пользовательского интерфейса Andoid <em>не</em> является потокобезопасным. Поэтому, вы не должны работать
220с пользовательским интерфейсом из рабочего потока. Манипуляции с пользовательским интерфейсом необходимо выполнять из
221потока пользовательского интерфейса. Таким образом, существует только два правила однопоточной модели Android:</p>
222
223<ol>
224<li>Не блокируйте поток пользовательского интерфейса
225<li>Не обращайтесь к набору инструментов пользовательского интерфейса Android снаружи потока пользовательского интерфейса
226</ol>
227
228<h3 id="WorkerThreads">Рабочие потоки</h3>
229
230<p>Вследствие описанной выше однопоточной модели для динамичности пользовательского интерфейса ваших приложений
231очень важно не блокировать поток пользовательского интерфейса. Если требуется выполнять операции,
232занимающие некоторое время, обязательно выполняйте их в отдельных потоках (»фоновых» или
233«рабочих» потоках).</p>
234
235<p>Например, ниже приведен код контроля нажатий, который загружает изображение из отдельного
236потока и отображает их в виджете {@link android.widget.ImageView}:</p>
237
238<pre>
239public void onClick(View v) {
240    new Thread(new Runnable() {
241        public void run() {
242            Bitmap b = loadImageFromNetwork("http://example.com/image.png");
243            mImageView.setImageBitmap(b);
244        }
245    }).start();
246}
247</pre>
248
249<p>На первый взгляд, он должен работать хорошо, так как он создает новый поток для обработки сетевой
250операции. Однако, он нарушает второе правило однопоточной модели: <em>не обращайтесь к набору инструментов пользовательского интерфейса
251Android снаружи потока пользовательского интерфейса</em> &mdash; этот пример изменяет {@link
252android.widget.ImageView} из рабочего потока, а не из потока пользовательского интерфейса. Это может привести
253к неопределенному и непредвиденному поведению, отследить которое будет трудно.</p>
254
255<p>Для устранения этой проблемы Android предлагает несколько путей доступа к потоку пользовательского интерфейса из других
256потоков. Ниже приведен список полезных методов:</p>
257
258<ul>
259<li>{@link android.app.Activity#runOnUiThread(java.lang.Runnable)
260Activity.runOnUiThread(Runnable)}</li>
261<li>{@link android.view.View#post(java.lang.Runnable) View.post(Runnable)}</li>
262<li>{@link android.view.View#postDelayed(java.lang.Runnable, long) View.postDelayed(Runnable,
263long)}</li>
264</ul>
265
266<p>Например, можно исправить приведенный выше код с помощью метода {@link
267android.view.View#post(java.lang.Runnable) View.post(Runnable)}:</p>
268
269<pre>
270public void onClick(View v) {
271    new Thread(new Runnable() {
272        public void run() {
273            final Bitmap bitmap = loadImageFromNetwork("http://example.com/image.png");
274            mImageView.post(new Runnable() {
275                public void run() {
276                    mImageView.setImageBitmap(bitmap);
277                }
278            });
279        }
280    }).start();
281}
282</pre>
283
284<p>Теперь реализация является потокобезопасной: сетевая операция выполняется из отдельного потока,
285тогда как {@link android.widget.ImageView} работает из потока пользовательского интерфейса.</p>
286
287<p>Однако по мере роста сложности, код такого типа может становиться запутанным и сложным
288для поддержания. Чтобы обрабатывать более сложные взаимодействия с рабочим потоком, можно
289использовать метод {@link android.os.Handler} в рабочем потоке для обработки сообщений, поступающих из потока
290пользовательского интерфейса. Вероятно, самым лучшим решением является расширение класса {@link android.os.AsyncTask},
291которое упрощает выполнение заданий рабочего потока, которые должны взаимодействовать с пользовательским интерфейсом.</p>
292
293
294<h4 id="AsyncTask">Использование AsyncTask</h4>
295
296<p>Метод {@link android.os.AsyncTask} позволяет выполнять асинхронную работу в пользовательском
297интерфейсе. Он выполняет операции блокирования в рабочем потоке и затем публикует результаты в потоке
298пользовательского интерфейса без необходимости самостоятельно обрабатывать потоки и/или обработчики.</p>
299
300<p>Для использования этого метода необходимо создать подкласс {@link android.os.AsyncTask} и реализовать метод обратного вызова {@link
301android.os.AsyncTask#doInBackground doInBackground()}, который работает в пуле
302фоновых потоков. Чтобы обновить пользовательский интерфейс, следует реализовать метод {@link
303android.os.AsyncTask#onPostExecute onPostExecute()}, который доставляет результат из {@link
304android.os.AsyncTask#doInBackground doInBackground()} и работает в потоке пользовательского интерфейса, так что вы можете безопасно
305обновлять пользовательский интерфейс. Задача выполняется через вызов метода {@link android.os.AsyncTask#execute execute()}
306из потока пользовательского интерфейса.</p>
307
308<p>Например, можно реализовать предыдущий пример с помощью метода {@link android.os.AsyncTask} следующим
309образом:</p>
310
311<pre>
312public void onClick(View v) {
313    new DownloadImageTask().execute("http://example.com/image.png");
314}
315
316private class DownloadImageTask extends AsyncTask&lt;String, Void, Bitmap&gt; {
317    /** The system calls this to perform work in a worker thread and
318      * delivers it the parameters given to AsyncTask.execute() */
319    protected Bitmap doInBackground(String... urls) {
320        return loadImageFromNetwork(urls[0]);
321    }
322
323    /** The system calls this to perform work in the UI thread and delivers
324      * the result from doInBackground() */
325    protected void onPostExecute(Bitmap result) {
326        mImageView.setImageBitmap(result);
327    }
328}
329</pre>
330
331<p>Теперь пользовательский интерфейс защищен и код стал проще, так как работа разделена на
332часть, которая должна выполняться в рабочем потоке, и часть, которая должна выполняться в потоке пользовательского интерфейса.</p>
333
334<p>Прочитайте статью {@link android.os.AsyncTask}, чтобы полностью понять
335использование этого класса. Здесь приведен краткий обзор его работы:</p>
336
337<ul>
338<li>Можно указывать тип параметров, значения хода выполнения и конечное
339значение задания с помощью универсальных компонентов</li>
340<li>Метод {@link android.os.AsyncTask#doInBackground doInBackground()} выполняется автоматически
341в рабочем потоке</li>
342<li>Методы {@link android.os.AsyncTask#onPreExecute onPreExecute()}, {@link
343android.os.AsyncTask#onPostExecute onPostExecute()} и {@link
344android.os.AsyncTask#onProgressUpdate onProgressUpdate()} запускаются в потоке пользовательского интерфейса</li>
345<li>Значение, возвращенное методом {@link android.os.AsyncTask#doInBackground doInBackground()}, отправляется в метод
346{@link android.os.AsyncTask#onPostExecute onPostExecute()}</li>
347<li>Можно вызвать {@link android.os.AsyncTask#publishProgress publishProgress()} в любой момент в {@link
348android.os.AsyncTask#doInBackground doInBackground()} для выполнения {@link
349android.os.AsyncTask#onProgressUpdate onProgressUpdate()} в потоке пользовательского интерфейса</li>
350<li>Задание можно отменить в любой момент из любого потока</li>
351</ul>
352
353<p class="caution"><strong>Предупреждение!</strong> Другая проблема, с которой вы можете столкнуться при использовании рабочего
354потока, состоит в непредсказуемом перезапуске действия вследствие <a href="{@docRoot}guide/topics/resources/runtime-changes.html">изменения конфигурации в режиме выполнения</a>,
355(например, когда пользователь изменяет ориентацию экрана), что может разрушить рабочий поток. Чтобы
356увидеть, как можно сохранить задание во время одного из подобных перезапусков и как правильно отменить задание
357при разрушении действия, изучите исходный код примера приложения <a href="http://code.google.com/p/shelves/">Shelves</a>.</p>
358
359
360<h3 id="ThreadSafe">Потокобезопасные методы</h3>
361
362<p> В некоторых ситуациях реализованные методы могут вызываться из нескольких потоков и, следовательно,
363должны быть написаны с сохранением потокобезопасности. </p>
364
365<p>В первую очередь это относится к методам, которые можно вызывать удаленно, например, к методам в <a href="{@docRoot}guide/components/bound-services.html">связанной службе</a>. Когда вызов
366метода реализуется в классе {@link android.os.IBinder}, происходящем из того же процесса, в котором выполняется
367{@link android.os.IBinder IBinder}, метод выполняется в потоке вызывающего метода.
368Однако, когда вызов происходит из другого процесса, метод выполняется в потоке, выбранном из пула
369потоков, которые система поддерживает в том же процессе, что и {@link android.os.IBinder
370IBinder} (он не выполняется в потоке пользовательского интерфейса процесса).  Например, поскольку метод
371{@link android.app.Service#onBind onBind()} службы будет вызываться из потока пользовательского интерфейса
372процесса службы, методы, реализованные в объекте, который возвращает {@link android.app.Service#onBind
373onBind()} (например, подкласс, который реализует методы RPC), будут вызываться из потоков
374в пуле. Так как служба может иметь несколько клиентов, несколько потоков из пула могут одновременно использовать
375один и тот же метод {@link android.os.IBinder IBinder}. Поэтому методы {@link android.os.IBinder
376IBinder} должны быть реализованы с сохранением потокобезопасности.</p>
377
378<p> Аналогичным образом поставщик контента может получать запросы данных, которые происходят из другого процесса.
379Хотя классы {@link android.content.ContentResolver} и {@link android.content.ContentProvider}
380скрывают подробности управления взаимодействием процессов, методы {@link
381android.content.ContentProvider}, которые отвечают на эти запросы, &mdash;методы {@link
382android.content.ContentProvider#query query()}, {@link android.content.ContentProvider#insert
383insert()}, {@link android.content.ContentProvider#delete delete()}, {@link
384android.content.ContentProvider#update update()} и {@link android.content.ContentProvider#getType
385getType()} &mdash;вызываются из пула потоков в процессе поставщика контента, а не в процессе
386потока пользовательского интерфейса.  Поскольку эти методы могут вызываться из любого числа потоков одновременно,
387они также должны быть реализованы с сохранением потокобезопасности. </p>
388
389
390<h2 id="IPC">Взаимодействие процессов</h2>
391
392<p>Система Android предлагает механизм взаимодействия процессов (IPC) с помощью удаленного вызова процедуры
393(RPC), при котором метод вызывается действием или другим компонентом приложения, но выполняется
394удаленно (в другом процессе) с возвратом всех результатов
395вызывающему компоненту. Это влечет разложение вызова метода и его данных до уровня, понятного
396операционной системе, передачу его из локального процесса и адресного пространства удаленному процессу и
397адресному пространству, а затем повторную сборку и восстановление вызова.  После этого возвращенные значения
398передаются в обратном направлении.  Система Android содержит все коды для выполнения этих механизмов IPC,
399так что вы можете сосредоточиться на определении и реализации программного интерфейса RPC. </p>
400
401<p>Для выполнения IPC приложение должно быть привязано к службе с помощью метода {@link
402android.content.Context#bindService bindService()}. Дополнительные сведения представлены в разделе <a href="{@docRoot}guide/components/services.html">Службы</a> руководства для разработчиков.</p>
403
404
405<!--
406<h2>Beginner's Path</h2>
407
408<p>For information about how to perform work in the background for an indefinite period of time
409(without a user interface), continue with the <b><a
410href="{@docRoot}guide/components/services.html">Services</a></b> document.</p>
411-->
412