Евгений Сенько.

Программирование приложений для мобильных устройств под управлением Android. Часть 2



скачать книгу бесплатно

© Евгений Владимирович Сенько, 2017


ISBN 978-5-4485-6607-3

Создано в интеллектуальной издательской системе Ridero

Это вторая часть книги, здесь рассмотрены: уведомления – Notifications, потоки и асинхронное выполнение задач – Threads & AsyncTask, работа с сетью, приемники широковещательных сообщений – Broadcast Receivers, оповещения – Alarms, графика и анимация, управление тачем и жестами, управление мультимедией – музыкой, видео и встроенной камерой, работа с датчиками, определение местоположения и привязка к картам, управление данными, а также классы ContentProvider и Service.

Часть 1 содержит шесть глав, описывающих основные принципы создания приложений, пользовательский интерфейс, полномочия приложений, а так же базовые классы: Activity, Intent, Fragment.

Книга предназначена для программистов, владеющих языком программирования Java и желающих освоить написание приложений, работающих под ОС Android. Книга является переводом общедоступных бесплатных англоязычных интернет ресурсов.

Notifications – Уведомления

Уведомление ? это сообщение, которое может быть выведено на экран за пределами обычного пользовательского интерфейса приложения. Например, предположим, что у вас есть приложение, которое может загрузить электронную книгу из Интернета. Во время загрузки пользователь может продолжить использовать приложение или даже выйти из него в то время, как книга загружается. И тогда вы, вероятно, захотите сообщить пользователю об окончании загрузки. Чтобы сделать это, вы должны выяснить, когда загрузка закончится, а затем вывести на экран сообщение об этом.

Далее рассмотрим два различных вида пользовательских уведомлений, которые поддерживает Android. Первый вид сообщения – тост (toast). Тост обеспечивает простую обратную связь от операции в небольшом всплывающем окне. Это окно занимает небольшое пространство, минимально необходимое для сообщения, а текущая Activity остается видимой и интерактивной.



Второй вид – уведомления в строке состояния (status bar) или области уведомлений. Когда приложение сообщает системе о необходимости выдать уведомление, оно сначала отображается в виде значка в области уведомлений в верхней части экрана слева.



Чтобы просмотреть подробные сведения об уведомлении, пользователь открывает панель уведомлений, «вытягивая» ее сверху.



Строкой состояния и панелью уведомлений управляет система, а пользователь может их просматривать в любое время. Такие уведомления обычно используются, чтобы объявить о непредсказуемых событиях и сделать это способом, который не прерывает текущую деятельность пользователя независимо от того, что он делает в этот момент.

Например, о входящей смс. Появление значка в области уведомлений говорит о том, что сообщение прибыло. Но это делается ненавязчивым способом – сообщение здесь, и вы свободны прочесть его тогда, когда это удобно для вас.

Итак, Android обеспечивает несколько различных видов пользовательских уведомлений. Эти уведомления – сообщения пользователю, которые отправляются по мере необходимости, и появляются они вне пользовательского интерфейса приложения. То есть и текст смс, который вы редактируете, и кнопка, которую вы нажмете, чтобы отправить сообщение, всегда видимы, пока вы сочиняете сообщение.

Тост-сообщения являются кратковременными сообщениями, которые разворачиваются на дисплее, например, чтобы дать пользователю знать об успешном завершении операции. Тосты автоматически постепенно появляются и постепенно исчезают. Их задача – предоставить информацию пользователю. Но они не предназначены для того, чтобы собирать информацию для передачи её обратно в приложение.

Для создания тоста, используется метод makeText класса Toast. Этот метод имеет два параметра: текст, который вы хотите вывести на экран, и количество времени, в течение которого текст должен быть видимым. После того, как вы создали тост, вы можете вывести его на экран, вызвав метод Toast.show ().

Теперь давайте посмотрим на пример приложения, которое использует тост-сообщения. Это приложение выводит на экран единственную кнопку, подписанную «Show Toast». Если нажать эту кнопку, то в нижней части экрана вы увидите маленькое раскрывающееся окно, которое говорит: «You’re toast!».



Теперь, если открыть исходный код приложения, мы увидим, как это реализовано.



Здесь вы видите OnClickListener для кнопки «Show Toast», а внутри – вызов метода makeText, передающий текст и константу Toast. LENGTH_LONG, которая делает текст видимым в течение приблизительно трех с половиной секунд. И в конце строки происходит вызов метода show (), который и выводит на экран тост.

Если вам не нравится стандартный вид тоста, вы можете создать кастом вью (пользовательское вью) для своего тоста. Например, вы можете создать кастом лейаут в XML и применить его, а затем присоединить созданную вью к тост-сообщению, вызвав метод setView.

Давайте посмотрим пример. Он во многом выглядит как предыдущий, но с той разницей, что здесь на экран выводится тост, созданный из пользовательской кастом вью.



Теперь давайте откроем основную Activity этого приложения и посмотрим, как был создан этот тост. Видно, что когда нажимается кнопка «Show Toast», код сначала создает новый объект тост-сообщения.



Следующие две строки устанавливают расположение тоста на экране и определяют отрезок времени, в течение которого сообщение будет видимым. Далее идет вызов setView, в котором первый параметр – результат применения XML-лейаута, который находится в пользовательском файле custom_toast. xml. В этом файле находится relativeLayout, содержащий два дочерних элемента. Первый – вью изображения, которое вы видите в тосте рядом с текстом. Второй – текстовое вью, которое выводит на экран текст «You’re toast!».

Затем, возвращаясь назад в основную Activity, в заключительной строке мы видим метод show (), который выводит созданный тост на экран.

Другой вид пользовательского уведомления, который мы рассмотрим – это уведомления, которые появляются в области уведомлений (status bar). Приложения и сама система Android могут использовать эту область, чтобы сообщить пользователю о возникновении различных событий. Область уведомлений также предоставляет такой элемент пользовательского интерфейса, как панель (drawer), которую пользователь может открыть, вытянув из области уведомлений сверху. И если её открыть, вы увидите дополнительную информацию о различных уведомлениях, которые были помещены в область уведомлений.

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



Когда пользователь отлучился из телефонного приложения, Android создал объект уведомления и поместил его в область уведомлений. Это уведомление служит напоминанием, что телефонное соединение все еще активно, а также служит способом быстро вернуться к этому телефонному вызову. Но в это время пользователь запустил браузер, где перешёл на www.google.com и выполняет поиск. Затем вооруженный информацией, в которой нуждался, он хочет вернуться к телефонному вызову. Тогда он вытягивает панель из области уведомлений, чтобы увидеть вьюшку, которая содержит некоторую информацию о вызове. Это позволяет ему либо вернуться к разговору, либо повесить трубку. Если он хочет продолжить разговор, то он кликнет по области уведомлений, и это переведёт телефонное приложение в рабочее состояние, вернет его на передний план и позволит пользователю продолжать разговор.

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

Теперь, когда вы создали уведомление, в какой-то момент вы захотите отправить его, затем обновить, отменить или что-то еще. Этими операциями управляет системная служба Android, называемая Менеджером уведомлений.

Давайте разберем два приложения, которые отправляют уведомления, и рассмотрим их исходный код, чтобы увидеть, как все это реализовано. Запустим приложение NotificationStatusBar. Пользовательский интерфейс содержит на экране единственную кнопку – «Notify». Если нажать эту кнопку, будет создано и отправлено уведомление и, в конечном счете, оно появится в панели уведомлений наверху экрана телефона.



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

А теперь откроем панель уведомлений. Вы видите, что вьюшка уведомления показывает иконку, текст заголовка уведомления, подробный текст уведомления, который показывает номер один в круглых скобках, указывая, что кнопка «Notify» была нажата один раз. И имеется также метка времени. Если закрыть панель уведомлений и нажать кнопку «Notify» еще раз, то текст уведомления будет обновлен, чтобы показать, что кнопка опять была нажата.



Далее, если кликнуть по самому уведомлению, вы увидите, что запустилась новая Activity, напечатав слова: «Got the Intent». Смысл в том, что вы можете присоединить Intent к вьюшке в панели уведомлений, чтобы переключить пользователя на приложение (или Activity), которое должно обработать то действие, о котором говорилось в уведомлении.

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

Теперь давайте рассмотрим код приложения с кастомной вью. Откроем основную Activity приложения.



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

Затем, код создает пользовательскую кастом вью, которая будет выведена на экран в панели уведомлений.



Лейаут этой вью находится в файле custom_notification. xml. Эта вью представляет собой linear layout с двумя дочерними вью. Первый – изображение глаза. А другой – текстовая вью, которая выводит на экран текст «You’ve been notified».

Далее в основной Activity идет метод onCreate. Здесь код создает Intent, названный mNotificationIntent, который явно активирует sub-Activity уведомления.



Следующая строка кода это неописанный прежде объект – PendingIntent, который основан на известном mNotificationIntent, созданный на предыдущей строке. PendingIntent описывает интент (Intent) и действие, которое надо с ним выполнить, позволяет стороннему приложению выполнять определенный код вашего приложения с правами, которые определены для вашего же приложения. То есть позволяет стороннему приложению, в которое его передали, запустить хранящийся внутри него интент, от имени того приложения (и теми же с полномочиями), передавшего этот PendingIntent.

Идем дальше, «слушатель» кнопки «Notify» сначала обновляет текст содержимого, который указывает число нажатий кнопки.



Затем он создает само уведомление, используя класс notification. builder. Код создает новый объект notification. Builder, устанавливает текст тиккера (бегущей строки), устанавливает маленькую иконку и затем устанавливает параметр auto cancel равным true. Это укажет системе отменить уведомление, когда пользователь кликнет по вьюшке в панели уведомлений. Затем устанавливается интент, тот самый PendingIntent, который определяет какое действие произвести, когда пользователь кликнет по вьюшке в панели уведомлений. Далее устанавливаются звуки и образцы вибрации, которые должны быть воспроизведены, когда прибывает уведомление. И наконец, устанавливается пользовательская вью, которая должна быть выведена на экран, когда пользователь раскрывает панель уведомлений.



Теперь, когда уведомление установлено, код получает ссылку на менеджера уведомлений вызовом getSystemService, передавая ID службы уведомлений. И наконец, код вызывает метод notify менеджера уведомлений, передавая ID уведомления в качестве параметра.



А метод build непосредственно и генерирует тот самый объект уведомления.

Потоки

Мобильные устройства, как и компьютеры, сегодня все чаще содержат по несколько вычислительных ядер. Это означает, что несколько программ могут работать на этих устройствах одновременно. И это – мощная вещь, потому что она позволяет производить больше вычислений за меньшее время. Но это также сделает ваши программы намного более сложными, что может привести к ошибкам и проблемам производительности, если вы, как разработчик, не будете внимательны и осторожны.

Для одновременно работающих программ и параллельно производимых вычислений используются Потоки – Threads. Концептуально поток – одно из многих возможных вычислений, работающих одновременно в операционной системе. С точки зрения реализации каждый поток имеет свой собственный счетчик команд и стек времени исполнения, но совместно использует «кучу» (структура данных, с помощью которой реализована динамически распределяемая память приложения) и области статического ЗУ с другими работающими потоками.

Диаграмма, изображающая эти понятия.



Здесь показано гипотетическое вычислительное устройство. У этого устройства есть два процессора, CPU 1 и CPU 2. Каждый из этих процессоров может выполнять инструкции приложений, работающих на устройстве. Далее на CPU 2 показаны два выполняющихся процесса – p3 и p4. Один из вариантов – рассматривать процессы как автономные среды исполнения. У них есть ресурсы, такие как память, открытые файлы, сетевые соединения и другие вещи, которыми они управляют и разделяют с другими процессами на устройстве. И в одном из этих процессов, p4, показаны два работающих потока – т7 и т8. Каждый из этих потоков – последовательно выполняющийся ряд инструкций со своим собственным стеком вызовов. Но так как они работают в одном и том же процессе, каждый из них может получить доступ к совместно используемым ресурсам этого процесса, включая статические переменные.

В Java потоки представлены объектом типа thread в пакете java.lang. Потоки в Java реализуют интерфейс runnable. Это означает, что у них должен быть открытый (public) метод называющийся run, который не получает параметров и у него нет возвращаемого значения. Среди методов потоки имеют метод start для запуска потока и метод sleep для того, чтобы временно приостановить выполнение потока. Метод wait заставляет поток приостановиться и ждать пока другой поток не разбудит его методом notify.

Чтобы использовать поток, во-первых, необходимо создать поток. Например, при помощи команды new. Далее, потоки автоматически не запускаются, чтобы запустить поток необходимо вызвать метод start. И, в конечном счете происходит вызов метода run, который будет выполняться до тех пор, пока не будет остановлен.

Работающее приложение дает команду new, чтобы создать объект – новый поток. Далее работа приложения продолжается, и когда-то позже произойдет вызов метода запуска потока start. При этом произойдет возврат к приложению, но параллельно начнет выполняться код в методе потока run. И, поскольку программа продолжается, то теперь одновременно выполняются два потока. Таким образом, проделав это многократно, можно создать и выполнять столько потоков, сколько необходимо.

Рассмотрим приложение, в котором поточная обработка была бы полезна, ThreadingNoThreading. Приложение выводит на экран простой пользовательский интерфейс с двумя кнопками. Первая кнопка маркирована «LoadIcon». Когда пользователь кликает по этой кнопке, приложение открывает и читает файл, содержащий изображение, и затем показывает его на дисплее. Идея здесь состоит в том, что эта работа может занимать значительное количество времени. В данном примере количество времени несколько преувеличено для наглядности. Некоторые операции занимают относительно большое количество времени. И разработчик должен это понимать и правильно манипулировать этим.

Вторая кнопка маркирована «Other Button». Когда пользователь кликает по этой кнопке, раскрывается тост-сообщение, выводя на экран некоторый текст. А здесь идея в том, что, если вы видите текст, значит кнопка работает. Соответственно, если вы не можете нажать кнопку или не видите текст, значит что-то работает неправильно.



В идеале пользователь должен быть в состоянии нажать любую из кнопок в любое время и получить реакцию, система просто должна работать. Давайте запустим версию этого приложения, которое не использует поточной обработки. Нажмем кнопку «Other Button», и на дисплее появляется обещанное сообщение.

А теперь поступим иначе. Сначала нажмем кнопку «Load Icon», которая запустит трудоемкую работу чтения битового массива из файла и вывода изображения на экран. И сразу же после нажатия кнопки «Load Icon», не дожидаясь появления картинки, нажмем кнопку «Other Button». И что же тогда произойдет? Кажется кнопка «Other Button» не работает. Почему? Потому что при попытке нажать «Other Button», Android все еще загружал картинку после нажатия кнопки «Load Icon» и это препятствовало тому, чтобы вторая кнопка сработала.

У этой проблемы есть одно на вид очевидное, но, в конечном счете, неправильное решение – перейти к «слушателю» кнопки «Load Icon» и просто создать новый поток, который будет загружать битовый массив и затем выведет его на экран. Пример такой реализации – приложение Threadingsimple, вот его код.



«Слушатель» кнопки «Load Icon» вызывает метод loadIcon (), который показан чуть ниже. Этот код создает новый поток, который занимает время, загружая битовый массив. И затем пытается установить изображение в image view, который является частью лейаута.



Теперь, если запустить приложение и нажать кнопку «Load Icon», а затем сразу нажать «Other Button», видно, что есть реакция на «Other Button» и её нажатие не блокируется. Это хорошо, есть прогресс. Однако появилась большая проблема, через несколько секунд приложение рухнуло.



Если исследовать журнал logcat, мы увидим, что есть сообщение о том, что только тот поток, в котором создана иерархия вьюшек, может манипулировать своими вьюшками.



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

И так, какой же поток на самом деле создал иерархию вьюшек этого приложения? У всех Android приложений есть основной поток, который также называют UI thread – потоком пользовательского интерфейса. Все компоненты приложения, которые работают в одном и том же процессе, запущенном по умолчанию, используют тот же поток – UI thread. Все методы жизненного цикла: OnCreate, OnStart и т.д., работают в основном потоке. И, кроме того, сам инструментарий пользовательского интерфейса не ориентирован на многопотоковое исполнение. Все это означает, что, если вы заблокируете UI-поток любой продолжительной работой, это воспрепятствует реакции приложения на другие манипуляции пользователя. Следовательно, долго выполняющиеся операции должны быть помещены в фоновые потоки. Однако, вместе с этим, мы не сможем получить доступ к инструментарию пользовательского интерфейса от потока, не принадлежащего UI tread. Таким образом, мы должны делать длительную работу в фоновом потоке, но когда эта работа сделана, мы должны сделать обновление пользовательского интерфейса в потоке UI.

И Android на самом деле дает нам набор средств сделать это. В частности Android обеспечивает несколько методов, которые гарантированно будут работать в потоке пользовательского интерфейса. Два из них – это метод post класса View и runOnUiThread класса Activity. Оба этих метода получают параметр Runnable, содержащий код, который, например, обновляет экран в наших недавних примерах. Таким образом, если мы используем эти методы, мы могли бы загрузить битовый массив в фоновом потоке, и когда эта операция завершится, мы использовали бы один из этих методов, чтобы выполнить Runnable, который и выведет изображение на экран.



скачать книгу бесплатно

страницы: 1 2 3

Поделиться ссылкой на выделенное