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>Запись манифеста для каждого типа элементов компонента —<a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code 47<activity>}</a>, <a href="{@docRoot}guide/topics/manifest/service-element.html">{@code 48<service>}</a>, <a href="{@docRoot}guide/topics/manifest/receiver-element.html">{@code 49<receiver>}</a> и <a href="{@docRoot}guide/topics/manifest/provider-element.html">{@code 50<provider>}</a> —поддерживает атрибут {@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<application>}</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}, которая выполняется "на переднем плане", — службу, 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> — этот пример изменяет {@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<String, Void, Bitmap> { 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}, которые отвечают на эти запросы, —методы {@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()} —вызываются из пула потоков в процессе поставщика контента, а не в процессе 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