Android extend activity class

Android extend activity class

Класс Activity — пожалуй самый важный класс, из которого строится приложение Android. Этот класс представляет визуальную активность приложения, и определяет действия, которые может производить пользователь. В Java-приложении должен быть как минимум один класс, который был расширен (extends) от родительского класса Activity. Поэтому важно знать и уметь применять методы класса Activity. В этой статье приведен перевод документации Google [1].

Класс Activity произошел (extends) от класса ContextThemeWrapper , и реализовал (implements) методы ComponentCallbacks2 , KeyEvent.Callback , LayoutInflater.Factory2 , View.OnCreateContextMenuListener , Window.Callback .

Иерархия классов, от которой произошел класс Activity: java.lang.Object -> android.content.Context -> android.content.ContextWrapper -> android.view.ContextThemeWrapper -> android.app.Activity .

Известные прямые наследники Activity (Direct Subclasses): AccountAuthenticatorActivity , ActivityGroup , AliasActivity , ExpandableListActivity , FragmentActivity , ListActivity , NativeActivity .

Известные непрямые наследники Activity (Indirect Subclasses): ActionBarActivity , LauncherActivity , PreferenceActivity , TabActivity .

[Обзор класса Activity]

Activity переводится как действие. Это некая сущность, олицетворяющая все, что может делать пользователь. Почти все экземпляры и разновидности activitу напрямую взаимодействуют с пользователем, так что класс Activity отвечает за создание окна, в котором Вы можете разместить свой визуальный интерфейс GUI вызовом setContentView(View). В то время как activitу часто представлены пользователю как окна, развернутые во весь экран, activitу может быть также использована и по-другому: как плавающее окно (с темой, где установлено свойство windowIsFloating), или activitу может быть встроена в другое activity (с использованием ActivityGroup). Каждое приложение, которое создается на Java, создает как минимум один подкласс, расширенный от класса Activity:

При этом в подклассе, произведенном от Activity обычно будет реализовано 2 метода:

onCreate(Bundle) здесь Вы инициализируете activity. Самое главное здесь вызвать setContentView(int), где int идентификатор ресурса, определяющего интерфейс пользователя (GUI), и использовать вызовы findViewById(int) для получения доступа к виджетам (контролам), с которыми нужно работать программно.
onPause() здесь Вы обрабатываете ситуацию, когда пользователь оставил работу с этим activity. Самое главное здесь — зафиксировать (запомнить) любые изменения, сделанные пользователем (обычно данные содержит в себе ContentProvider).

Чтобы можно было использовать activity вместе с Context.startActivity(), все классы activity classes должны иметь соответствующие описания — декларацию в файле AndroidManifest.xml пакета приложения.

В этой статье будут рассмотрены следующие темы:

1. Фрагменты (Fragments).
2. Жизненный цикл activity.
3. Изменения конфигурации.
4. Запуск Activitу и получение результатов.
5. Сохранение определенного состояния (Persistent State).
6. Разрешения (Permissions).
7. Жизненный цикл процесса.

Класс Activity является важной частью приложения в любой момент жизни приложения, и метод запуска экземпляров activity и их комбинирования является фундаментальной основой модели приложения платформы Android. Чтобы подробно рассмотреть перспективу и структуру приложения и как при этом ведут себя активности, пожалуйста прочитайте руководства разработчика «Application Fundamentals» (основы приложения) и «Tasks and Back Stack» (задачи и обратный стек). Вы также можете найти детальное обсуждение вопросов создания активностей в документации по использованию Activity.

[Фрагменты]

Начиная с версии Android HONEYCOMB реализации класса Activity могут использовать класс Fragment , чтобы лучше разделить код на модули, и создать более сложный интерфейс пользователя, который поможет подстроить приложение под разные типы экрана — большие и маленькие.

[Жизненный цикл activity (Activity Lifecycle)]

Активности в системе обрабатываются как стек активностей. Когда запущена новая активность, она помещается наверх стека и становиться работающей активностью (running activity) — при этом предыдущая активность остаются всегда ниже в стеке, и не переходит в снова верхнее положение пока существует новая активность.

У активность по существу есть 4 состояния:

• Если активность находится на передней части экрана (наверху стека), то она считается активной или работающей (running).
• Если активность потеряла фокус, но все еще видима (т. е. новая полноэкранная или полупрозрачная активность получает фокус и располагается выше Вашей активности), то считается, что активность находится в состоянии паузы (paused). Активность в состоянии паузы полностью живая (поддерживает все состояние и информацию об элементе, и остается подключенной к менеджеру окон), однако может быть убита системой в ситуациях экстремальной нехватки памяти.
• Если активность полностью затенена другой активностью, то она останавливается. Остановленная активность все еще сохраняет свое состояние и информацию об элементе, однако она больше не видна пользователю и её окно скрыто, и скорее всего такая активность будет убита системой, когда память понадобиться для чего-то еще.
• Если активность находится на паузе или в состоянии останова, система может выкинуть её из памяти либо путем запроса завершения приложения, либо простым прибиванием её процесса. когда активность будет снова отображена для пользователя, она должна быть полностью запущена заново и восстановлена в своем предыдущем состоянии.

На следующей диаграмме показано, какие важные состояния проходит Activity и в каком порядке. Серые прямоугольники показывают методы обратного вызова (callback methods), которые Вы можете реализовать для выполнения операций, когда Activity переходит между состояниями. Цветные овалы представляют основные состояния Activity, в которых она может находиться.

Есть три ключевых цикла, которые интересны в отслеживании состояния активности:

entire lifetime (полное время жизни) activity отсчитывается с момента первого вызова onCreate(Bundle) до последнего одиночного вызова onDestroy(). Активность делает все настройки своего «глобального» состояния в теле onCreate(), и освобождает все занятые ресурсы в теле onDestroy(). Например, если в фоне запущен поток, который загружает данные по сети, то этот поток может быть создан в теле onCreate() и остановлен в теле onDestroy().
visible lifetime (видимое время) activity отсчитывается между вызовом onStart() до соответствующего вызова onStop(). В течение этого времени пользователь может видеть работу активности на экране, хотя это может быть не на переднем плане и во взаимодействии с пользователем. Между этими двумя методами Вы можете удерживать ресурсы, которые нужны для отображения активности для пользователя. Например, Вы может зарегистрировать BroadcastReceiver в теле onStart() для отслеживания изменений, которые происходят в графическом интерфейсе пользователя, и дерегистрировать его в onStop(), когда пользователь больше не видит отображение активности. Методы onStart() и onStop() могут быть вызваны несколько раз, как только активность становиться видимой и невидимой для пользователя.
foreground lifetime (время верхнего состояния) происходит между вызовом onResume() до соответствующего вызова onPause(). В течение этого времени активность находится на верхнем уровне (поверх всех других активностей), и может взаимодействовать с пользователем. Активность может часто переходить между состоянием продолжения работы в состоянием паузы — например, когда устройство переходит в состояния сна, когда доставлен результат работы активности, кода поставлен новый intent is delivered — так что код в этих методах должен быть довольно простым и нересурсоемким.

Читайте также:  Взломанный клеш рояль андроид

Полный жизненный цикл активности определяется следующими методами класса Activity. Все эти хуки могут быть перезаданы (override), чтобы они делали нужную работу при изменении состояния активности. Все активности будут реализовывать onCreate(Bundle) для выполнения своей первоначальной настройки; часто также нужно реализовать onPause(), чтобы принять изменения данных или в другом случает подготовиться к остановке взаимодействия с пользователем. Вы должны всегда вызвать свой суперкласс (класс-родитель), когда реализуете эти методы.

Обычно перемещения жизненного цикла активности выглядят так:

Метод Описание Killable
(может быть
убито
системой)?
Следующее
состояние
onCreate() Будет вызвано, когда активность создается в первый раз. В этом месте Вам нужно сделать все начальные статические настройки: создание видов (view), привязать данные к спискам, и т. д. Этот метод также предоставляется Вам вместе с Bundle, содержащим предыдущее замороженное (сохраненное) состояние активности, если оно было. За этим методом обязательно последует вызов onStart() . Нет onStart()
onRestart() Вызывается после того, как Ваша активность была остановлена перед тем, как запустить её снова. За этим методом обязательно последует вызов onStart() Нет onStart()
onStart() Вызывается, когда активность становится видимой для пользователя. Сопровождается вызовом onResume() , если активность перешла на передний план (foreground), или onStop() , если становится скрытой. Нет onResume()
или
onStop()
onResume() Вызывается, когда активность начала взаимодействовать с пользователем. В этой точке Ваша активность находится на вершине стека активностей, и пользователь что-то вводит на ней. За этим методом всегда следует вызов onPause() . Нет onPause()
onPause() Вызывается, когда система намеревается возобновление работы предыдущей активности. Этот метод обычно используется для сохранения всех изменений в постоянные данные (persistent data), остановки анимаций и других вещей, которые требуют вычислительных ресурсов CPU, и т. д. Реализации этого метода должны отрабатывать очень быстро, потому что следующая активность не будет возобновлена, пока не произойдет выход из этого метода. За вызовом этого метода последует либо onResume() , если активность возвращается на передний план, или onStop() , если она становится невидимой для пользователя. До
HONEYCOMB
onResume()
или
onStop()
onStop() Вызывается, когда активность больше невидима для пользователя, потому что возобновила работу другая активность, и закрыла собой эту. Такое может случиться либо потому что запущена новая активность, либо потом что уже запущенная активность снова получает фокус, или когда эта активность уничтожается. За этим методом последует либо onRestart() , если активность возвращается к взаимодействию с пользователем, или onDestroy() , если активность умирает. Да onRestart()
или
onDestroy()
onDestroy() Завершающий вызов перед тем, как активность будет уничтожена. Это может произойти либо по причине завершения активности (в ней может быть вызван метод finish() , или потому что система временно уничтожает этот экземпляр активности, чтобы освободить память. Вы можете отличать эти два случая друг от друга с помощью метода isFinishing() . Да нет ничего

Обратите внимание на столбец Killable в этой таблице — для тех методов, которые помечены прибиваемыми, после того как этот метод завершился, то процесс, принадлежащий активности, может быть убит системой в любое время без какого-нибудь дополнительного выполнения кода. Поэтому Вы должны использовать метод onPause(), чтобы записать определенные данные (такие например, которые редактирует пользователь) в хранилище. Дополнительно метод onSaveInstanceState(Bundle) вызывается перед помещением активности в такое фоновое состояние, что позволяет Вам сохранить любое динамическое состояние Вашей активности в указанный Bundle, чтобы позднее принять в onCreate(Bundle), если активность должна быть создана заново. См. секцию «Жизненный цикл процесса» для получения дополнительной информации, как жизненный цикл процесса привязан к активности. Имейте в виду, что важно сохранять имеющиеся данные (persistent data) в onPause() вместо onSaveInstanceState(Bundle), потому что последний не является частью функций обратного вызова жизненного цикла, так что не будет вызван в каждой ситуации, как отписано в её документации.

Примечание: имейте в виду, что эти семантики незначительно изменяются между приложениями, которые предназначаются для платформ, начиная с HONEYCOMB, и более ранними платформами. Начиная с Honeycomb приложения не могут быть завершены пока не закончиться работа onStop(). Это влияет, когда может быть вызван onSaveInstanceState(Bundle) (он может быть безопасно вызван после onPause() и позволяет приложению безопасно ожидать, пока onStop() сохранит постоянное состояние (persistent state).

Для методов, которые не помечены как убиваемые, процесс активности не будет прибит системой от момента вызова метода до продолжения после возврата. Таким образом, активность не находится в том состоянии, когда её можно убить, например от момента после onPause() до старта onResume().

[Изменения конфигурации]

Если конфигурация устройства (как задано классом Resources.Configuration) изменилась, то все, что показывается в интерфейсе пользователя должно быть обновлено, чтобы соответствовать этой новой конфигурации. Поскольку Activity является главным механизмом для организации интерфейса с пользователем, в нем имеется специальная поддержка обработки ситуаций изменения конфигурации.

Если Вы не задали это иначе, изменение конфигурации (такие как изменение ориентации экрана, языка, устройств ввода и т. д.) приведут к уничтожению текущей активности с проходом всех процессов жизненного цикла активности onPause(), onStop() и onDestroy(), как и положено. Если активность была на верхнем уровне (в состоянии работы) или видима для пользователя, как только вызван onDestroy() в том экземпляре активности, то будет создан новый экземпляр активности, с любым savedInstanceState, ранее сгенерированным из onSaveInstanceState(Bundle).

Так происходит потому, что любой ресурс приложения, включая файлы разметки интерфейса (layout files), могут быть изменены на основании любого значения конфигурации. Таким образом, единственный безопасный способ обработать изменение конфигурации состоит в том, чтобы повторно получить все ресурсы, включая разметки (layouts), изображения (drawables) и строки (strings). Поскольку активности должны уже знать, как сохранить свое состояние и заново воссоздать себя из этого состояния, это удобный способ, чтобы активность перезапустила самого себя с новой конфигурацией.

В некоторых особых случаях Вы можете захотеть пропустить перезапуск активности на основании одного или нескольких типов изменения конфигурации. Это делается через атрибут android:configChanges в манифесте. Для любого типа изменения конфигурации Вы там указываете, что будете делать отдельную обработку, и вместо перезапуска активности будете получать вызов метода onConfigurationChanged(Configuration). Если изменение конфигурации вовлекает что-то, что Вы не обрабатываете, то все-таки активность будет перезапущена, и метод onConfigurationChanged(Configuration) не будет вызван.

[Запуск Activitу и получение результатов]

Метод startActivity(Intent) используется для запуска новой дочерней активности, которая будет помещена на самый верх стека активностей. Метод принимает один аргумент Intent, который описывает активность, которая будет выполнена.

Иногда Вам понадобится получить результат от дочерней активности, когда она завершит работу. Например, Вы можете запустить активность, которая позволяет выбрать человека из списка контактов; когда эта активность завершится, она возвратит в родительскую активность выбранную персону. Чтобы сделать это, вызовите версию метода startActivityForResult(Intent, int) , где второй параметр идентифицирует вызов. Результат будет получен через вызов метода onActivityResult(int, int, Intent) .

Когда дочерняя активность завершается, она должна вызвать setResult(int) , чтобы вернуть данные в код, который её вызвал (в код родителя). Всегда должен быть предоставлен код результата, который может быть стандартными результатами RESULT_CANCELED, RESULT_OK, или это могут быть любые пользовательские значения, начинающиеся с RESULT_FIRST_USER. Дополнительно обратно может быть возвращен Intent, содержащий добавочные данные, если это требуется. Вся эта информация возвращается обратно в родительский метод Activity.onActivityResult() вместе с первоначально предоставленным (при вызове активности) целочисленным идентификатором.

Если дочерняя активности рухнула по какой то причине (программная ошибка или сбой), родительская активность получит в виде результата код RESULT_CANCELED.

[Сохранение определенного состояния (Persistent State)]

Прим. переводчика: термин Persistent State решил не переводить как «определенное состояние» или «постоянное состояние» (потому что смысл теряется и звучит не по-русски), и оставить как есть; под этими словами подразумеваются некоторые рабочие данные, которые нужно сохранить.

Есть обычно два вида Persistent State, с которыми активность имеет дело: совместно используемые данные наподобие редактируемого документа (обычно сохраняются в базе данных SQLite с использованием провайдера контента content provider ), и некое внутреннее состояние, такое как пользовательские настройки.

Для данных провайдера контента (content provider) рекомендуется использовать активностью модели пользователя «edit in place» (редактирование на месте). Это означает, что любое сделанное пользователем редактирование приводится в действие немедленно, без дополнительного шага подтверждения (прим. переводчика: непривычная с точки зрения пользователя PC модель, который привык к набившим оскомину кнопкам OK, Cancel, Apply). Поддержка этой модели изменения настроек (или документа) обычно проста, если следовать двум правилам:

• Когда создается новый документ, немедленно создается база данных бекапа или файл. Например, если пользователь начал писать новый e-mail, создается новая запись для письма и сразу в момент начала ввода данных, и если пользователь перейдет к другой активности из точки редактирования письма, то это (не доредактированное до конца) письмо появится в списке черновиков.
• Когда вызывается метод активности onPause(), он должен сохранить все данные в контент-провайдере или в файле любые изменения, которые сделал пользователь. Это предоставит возможность снова увидеть эти данные из другой активности, которая запустится. Возможно Вы решите сохранять данные более агрессивно, в ключевые моменты времени в течение жизненного цикла активности: например перед запуском новой активности, перед завершением собственной активности, когда пользователь переключается между полями ввода, и т. п.

Эта модель редактирования и сохранения данных разработана, чтобы предотвратить потерю данных, когда пользователь переходит от одной активности к другой, и позволяет системе безопасно убивать активность (потому что системные ресурсы не безграничны, и могут понадобиться для других целей) в любое время, как только активность приостановлена. Имейте в виду, что это подразумевает, что когда пользователь нажимает BACK (назад, выход) из Вашей активности, то это не означает «cancel» (отменить) — это означает покинуть активность с её текущим состоянием, которое должно быть сохранено. Отмена сделанных в активности изменений должна быть предоставлена неким другим механизмом, как например явный откат (revert) или опции отменить (undo).

См. content package для дополнительной информации про контент-провайдеров (content provider). Это ключевой аспект того, как активности вовлекаются в работу и обмениваются данными друг с другом и с самими собой.

Класс Activity также предоставляет API для управления внутренним persistent state, который связан с активностью. Это может использоваться, например, чтобы запомнить понравившийся стартовый экран в календаре (вид по дням или вид по неделям), или страничку по умолчанию в or the user’s default home page in a web browser.

Persistent state активности управляется с помощью метода getPreferences(int), что позволяет Вам получить и модифицировать набор пар name/value, связанных с активностью. Чтобы использовать свойства (preferences), которые являются общими между несколькими компонентами приложения (activities, receivers, services, providers), Вы можете использовать нижележащий метод Context.getSharedPreferences(), чтобы получить свойства объекта, сохраненного по специфическому имени. Имейте в виду, что невозможно сделать общими данные настроек между пакетами приложения — для этого нужен контент-провайдер (content provider).

Имеется исключение для активности календаря (calendar activity), которая сохраняет выбранный пользователем вид в его persistent settings:

[Права на доступ (Permissions)]

Возможность запустить определенное Activity будет осуществлена, если в её файле манифеста декларирован тег . При этом другие приложения должны декларировать соответствующий элемент в своем собственном манифесте, чтобы они могли запустить это activity.

Когда запускаете Activity, Вы можете установить Intent.FLAG_GRANT_READ_URI_PERMISSION и/или Intent.FLAG_GRANT_WRITE_URI_PERMISSION в объекте Intent. Это предоставит для Activity доступ к специфическим URI в Intent. Доступ будет оставаться активным, пока Activity не завершится (это остается, пока не будет убит хост-процесс, или другое временное разрушение). Начиная с версии GINGERBREAD, если Activity было уже создано и новый Intent передан в onNewIntent(Intent), любые недавно предоставленные URI permissions будут добавлены к уже существующим и предоставленным. Подробности см. в документе «Security and Permissions».

[Жизненный цикл процесса (Process Lifecycle)]

Система Android пытается сохранить процесс приложения рабочим настолько долго, как только это возможно, однако бывает нужно удалить старые процессы из памяти, когда кончается оперативная память. Как было описано в разделе «Жизненный цикл activity (Activity Lifecycle)» решение об удалении каждого конкретного процесса принимается на основании состояния взаимодействия пользователя с ним. В целом есть 4 состояния, в котором находится процесс, и эти состояния определяются на основе действий, работающих в нем. Ниже эти состояния перечислены в порядке уменьшения их важности. Система в первую очередь будет убивать наименее важные процессы (последние в списке), прежде чем удалить те, которые находятся в списке важности выше.

1. Foreground activity (активность, которая находится на переднем плане экрана, и с которой работает пользователь) считается наиболее важной. Этот процесс будет уничтожен только в последнюю очередь, если он будет больше памяти, чем доступно в устройстве Android. Если удаление все-таки произошло, то в этот момент устройство получило чрезмерно фрагментированную память, так что удаление процесса требуется, чтобы сохранить быструю работу интерфейса с пользователем.
2. Visible activity (активность, которая видима для пользователя, но она не находится в состоянии foreground, например окно находится внизу, под окошком foreground диалога) считается очень важной, и она не будет убита, пока это не потребуется для сохранения работоспособности foreground-активности.
3. Background activity (активность, которая не видна на экране для пользователя, и находится в состоянии паузы) больше не является критичной, так что система может её безопасно прибить, чтобы освободить память для других более важных процессов. Если процесс этой активности нужно убить, то когда пользователь возвращается обратно к этой активности (снова делает его видимым на экране), будет вызван его метод onCreate(Bundle) с savedInstanceState, ранее предоставленным в onSaveInstanceState(Bundle), так что активность может быть перезапущена в том же самом состоянии, в каком её оставил пользователь.
4. Empty process (пустой процесс), который не хостит активностей или другие компоненты приложения (такие как классы Service или BroadcastReceiver). Они будут убиты очень быстро, как только остается мало памяти. Поэтому любая фоновая работа, которую Вы выполняете за пределами активности, должна выполняться в контексте активности BroadcastReceiver или Service, чтобы обеспечить, что система знает о необходимости иметь в наличии Ваш процесс.

Иногда Activity может нуждаться в длительно запущенных операциях, которые существуют независимо от жизненного цикла активности как таковой. Например приложение камеры, которая выгружает картинку на web-сайт. Выгрузка может занять продолжительное время, и приложение должно предоставить пользователю возможность покинуть приложение, пока оно все еще работает. Чтобы выполнить это, Ваша Activity должно запустить Service, в которой как раз будет происходить выгрузка. Это позволяет системе правильно приоритизировать Ваш процесс (рассмотреть, какой процесс более важен среди невидимых приложений) в течение выгрузки, независимо от того, была ли оригинальная активность на паузе, остановлена или завершена.

[Общее описание констант, полей и методов]

Источник

Читайте также:  Armored warfare проект армата android
Оцените статью