Главная страница
Образовательный портал Как узнать результаты егэ Стихи про летний лагерь 3агадки для детей
qrcode

Программирование под Android. Для профессионалов


Скачать 19.35 Mb.
НазваниеПрограммирование под Android. Для профессионалов
АнкорBrayn Khardi Bill Fillips - Programmirovanie po.
Дата23.05.2017
Размер19.35 Mb.
Формат файлаpdf
Имя файлаBrayn_Khardi_Bill_Fillips_-_Programmirovanie_po.pdf
оригинальный pdf просмотр
ТипДокументы
#21061
страница47 из 55
КаталогОбразовательный портал Как узнать результаты егэ Стихи про летний лагерь 3агадки для детей
Образовательный портал Как узнать результаты егэ Стихи про летний лагерь 3агадки для детей
1   ...   43   44   45   46   47   48   49   50   ...   55
Глава 30. Широковещательные интенты
Подробнее об уровнях защиты
Каждое пользовательское разрешение должно задавать уровень защиты — атрибут android:protectionLevel
. Уровень защиты сообщает Android, как будет использо- ваться разрешение. В нашем примере используется уровень защиты signature
. Он означает, что если другое приложение захочет использовать ваше разрешение, то оно должно быть снабжено цифровой подписью с таким же ключом, как у вашего приложения. Обычно этот вариант оптимален для разрешений, используемых в ва- шем приложении. Так как ваш ключ недоступен для других разработчиков, они не могут получить доступ к функциональности, которую защищает ваше разрешение.
Вдобавок, поскольку у вас есть собственный ключ, вы можете использовать раз- решение в других приложениях, которые будут написаны позднее.
Таблица 30.1. Значения атрибута protectionLevel
Значение
Описание
normal
Используется для защиты функциональности приложения, кото- рая не выполняет потенциально опасных операций — например, обращений к защищенным личным данным или отправки данных в Интернет. Пользователь видит разрешение перед установкой приложения, но не получает запроса на его явное предоставле- ние. android.permission.RECEIVE_BOOT_COMPLETED использует этот уровень, как и разрешение на вибрацию телефона. Считай- те, что речь идет о функциях, которые сами по себе не опасны, но вы хотите информировать пользователя о том, что они будут задействованы dangerous
Используется для всего, для чего не используется normal — для обращений к личным данным, отправки и получению данных из сетевых интерфейсов, обращению к оборудованию, которое может использоваться для шпионских целей, и вообще всему, что может создать реальные проблемы для пользователя. В част- ности, разрешения на доступ к Интернету, камере и контактам относятся к этой категории. Android может запросить у пользова- теля подтверждение на выполнение опасной операции signature
Система предоставляет это разрешение, если приложение под- писано тем же сертификатом, что и приложение, в котором объявлено разрешение, или отклоняет его в противном случае.
Если разрешение предоставляется, пользователь об этом не опо- вещается. Значение обычно используется для функциональности, внутренней для вашего приложения — так как у вас имеется сертификат, а приложение может использоваться только прило- жениями, подписанными тем же сертификатом, вы контролируете состав пользователей разрешения. В нашем случае значение не позволит посторонним видеть нашу широковещательную рас- сылку, но при желании вы можете написать другое приложение, которое также сможет ее прослушивать signatureOrSystem
Аналог signature, но разрешение также предоставляется всем пакетам в образе системы Android. Используется для взаимодей- ствия с приложениями, встроенными в образ системы, так что для вас, скорее всего, интереса не представляет

Фильтрация оповещений переднего плана
503
Получение результатов с упорядоченной
широковещательной рассылкой
Мы организовали собственную широковещательную закрытую рассылку, но до сих пор передача данных осуществлялась только в одном направлении.
Приемник 1
Приемник 2
Рис. 30.4. Обычные широковещательные интенты
Это объяснялось тем, что концептуально обычный широковещательный интент принимается всеми одновременно. Сейчас onReceive(…)
вызывается в главном по- токе, поэтому на практике приемники не выполняются параллельно. Мы не можем рассчитывать на то, что они будут выполняться в каком-то конкретном порядке, или узнать, когда все они завершат выполнение. Этот факт значительно затруд- няет взаимодействие между широковещательными приемниками или получение информации отправителем интента от приемников.
Приемник
ответа
Приемник 1
Приемник 2
Рис. 30.5. Упорядоченные широковещательные интенты
Двустороннее взаимодействие можно реализовать с использованием упорядоченных
широковещательных интентов
. Упорядоченные широковещательные интенты по- зволяют серии широковещательных приемников обработать широковещательный интент по порядку. Кроме того, отправитель широковещательного интента может получать результаты, передавая при вызове специальный широковещательный приемник, называемый получателем результата (result receiver).

504
Глава 30. Широковещательные интенты
На получающей стороне все выглядит практически так же, как при обычной широко- вещательной рассылке. Однако в вашем распоряжении появляется дополнительный инструмент: набор методов, используемых для изменения возвращаемого значения вашего приемника. В нашей ситуации нужно отменить оповещение; эта информация передается в виде простого целочисленного кода результата. Соответственно мы используем метод setResultCode(int)
для назначения кода результата
Activity.
RESULT_CANCELED
Внесите изменения в
VisibleFragment
, чтобы вернуть информацию отправителю
SHOW_NOTIFICATION
Листинг 30.11. Возвращение простого результата (VisibleFragment.java)
private BroadcastReceiver mOnShowNotification = new BroadcastReceiver() {
@Override public void onReceive(Context context, Intent intent) {
Toast.makeText(getActivity(),
"Got a broadcast:" + intent.getAction(),
Toast.LENGTH_LONG)
.show();
Log.i(TAG, "canceling notification");
setResultCode(Activity.RESULT_CANCELED);
}
};
Так как в нашем примере необходимо лишь подать сигнал «да/нет», нам достаточно кода результата. Если потребуется вернуть более сложные данные, используйте setResultData(String)
или setResultExtras(Bundle)
. А если вы захотите задать все три значения, вызовите setResult(int,String,Bundle)
. После того как все возвращаемые значения будут заданы, каждый последующий приемник сможет увидеть или изменить их.
Чтобы эти методы делали что-то полезное, широковещательная передача должна быть упорядоченной. Напишите новый метод для отправки упорядоченных широ- ковещательных интентов из
PollService
. Этот метод будет упаковывать обраще- ние к
Notification и отправлять его в широковещательном режиме. Получатель результата будет отправлять упакованный объект
Notification
(при условии, что он не был отменен).
Листинг 30.12. Отправка упорядоченных широковещательных интентов (PollService.java)
void showBackgroundNotification(int requestCode, Notification notification) {
Intent i = new Intent(ACTION_SHOW_NOTIFICATION);
i.putExtra("REQUEST_CODE", requestCode);
i.putExtra("NOTIFICATION", notification);
sendOrderedBroadcast(i, PERM_PRIVATE, null, null,
Activity.RESULT_OK, null, null);
}
Метод
Context.sendOrderedBroadcast(Intent,String,BroadcastReceiver,Handle r,int,String,Bundle)
имеет пять дополнительных параметров кроме используе- мых в sendBroadcast(Intent,String)
. Вот они, по порядку: получатель результата, объект
Handler для запуска получателя результата, а затем исходные значения

Фильтрация оповещений переднего плана
505
кода результата, данных результата и дополнения результата для упорядоченной широковещательной рассылки.
Получатель результата — специальный приемник, который выполняется после всех остальных приемников упорядоченного широковещательного интента. В других обстоятельствах мы смогли бы использовать получателя результата для получения широковещательного интента и отправки объекта оповещения. Однако в данном случае такое решение не сработает. Широковещательный интент часто будет от- правляться непосредственно перед прекращением существования
PollService
. Это означает, что и приемник широковещательного интента может быть мертв.
Таким образом, последний приемник должен быть автономным. Создайте новый субкласс
BroadcastReceiver с именем
NotificationReceiver
. Реализуйте его сле- дующим образом.
Листинг 30.13. Реализация получателя результата (NotificationReceiver.java)
public class NotificationReceiver extends BroadcastReceiver {
private static final String TAG = "NotificationReceiver";
@Override
public void onReceive(Context c, Intent i) {
Log.i(TAG, "received result: " + getResultCode());
if (getResultCode() != Activity.RESULT_OK)
// Активность переднего плана отменила
// широковещательную передачу
return;
int requestCode = i.getIntExtra("REQUEST_CODE", 0);
Notification notification = (Notification)
i.getParcelableExtra("NOTIFICATION");
NotificationManager notificationManager = (NotificationManager)
c.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(requestCode, notification);
}
}
Наконец, зарегистрируйте новый приемник. Поскольку он отправляет оповещение, получая набор результатов от других приемников, он должен выполняться после всех остальных. Это означает, что приемнику нужно назначить низкий приоритет.
Так как он должен выполняться последним, назначьте ему приоритет –999 (значе- ния –1000 и ниже зарезервированы).
А поскольку приемник используется только во внутренней работе приложения, его не обязательно делать видимым извне. Задайте атрибут android:exported="false"
, чтобы ограничить доступ к приемнику.
Листинг 30.14. Регистрация приемника оповещений (AndroidManifest.xml)
... >
продолжение


506
Глава 30. Широковещательные интенты
Листинг 30.14 (продолжение)
... >






android:exported="false">

android:priority="-999">

android:name="com.bignerdranch.android.photogallery.SHOW_NOTIFICATION"
/>




Теперь используйте для отправки оповещения свой новый метод вместо
Notifi- cationManager
Листинг 30.15. Последний шаг (PollService.java)
@Override public void onHandleIntent(Intent intent) {
if (!resultId.equals(lastResultId)) {
Notification notification = new NotificationCompat.Builder(this)
.build();
NotificationManager notificationManager = (NotificationManager)
getSystemService(NOTIFICATION_SERVICE);
notificationManager.notify(0, notification);
sendBroadcast(new Intent(ACTION_SHOW_NOTIFICATION), PERM_PRIVATE);
showBackgroundNotification(0, notification);
}
prefs.edit()
.putString(FlickrFetchr.PREF_LAST_RESULT_ID, resultId)
.commit();
}
Запустите приложение PhotoGallery и пару раз переключите режим фонового опроса. Вы увидите, что оповещения перестают появляться. Чтобы убедиться в том, что оповещения все еще работают в фоновом режиме, снова задайте значение

Приемники и продолжительные задачи
507
PollService.POLL_INTERVAL
равным 5 секундам, чтобы вам не пришлось ждать целых пять минут.
Приемники и продолжительные задачи
Что же делать, если вы хотите, чтобы широковещательный интент запускал задачу более продолжительную, чем допускают ограничения главного цикла выполнения?
Есть два варианта. Первый — выделить эту работу в службу и запустить ее в ши- роковещательном приемнике. Мы рекомендуем использовать именно этот способ.
Служба может обрабатывать запрос столько времени, столько потребуется. Она может создать очередь из нескольких запросов и обслуживать их по порядку или обрабатывать запросы так, как считает нужным.
Второй вариант основан на использовании метода
BroadcastReceiver.goAsync()
Этот метод возвращает объект
BroadcastReceiver.PendingResult
, который может использоваться для передачи результата в будущем. Таким образом, вы передаете объект
PendingResult экземпляру
AsyncTask для выполнения продолжительной работы, а потом отвечаете на широковещательную передачу, вызывая методы
PendingResult
У этого способа есть два недостатка. Во-первых, он недоступен на старых устрой- ствах. Во-вторых, он менее гибок: вам все равно приходится обрабатывать широко- вещательную передачу за десять секунд или около того и в вашем распоряжении меньше архитектурных вариантов, чем при использовании службы.
Конечно, у метода goAsync()
есть одно огромное преимущество: в нем можно за- давать результаты упорядоченных широковещательных интентов. Если вам нужно именно это, другие решения не подойдут. Только позаботьтесь о том, чтобы выпол- нение не заняло слишком много времени.

Просмотр веб-страниц
и WebView
С каждой фотографией, загружаемой с Flickr, связана страница. В этой главе мы сделаем так, чтобы пользователь мог нажать на фотографии в PhotoGallery и просмо- треть ее страницу. Вы освоите два разных способа интеграции веб-контента в ваши приложения. Первый способ работает с браузером, установленным на устройстве, а второй использует класс
WebView для отображения веб-контента.
И еще один блок данных Flickr
Для обоих способов нам понадобится URL-адрес страницы фотографии на Flickr.
Если присмотреться к разметке XML, которую мы в настоящее время получаем для каждой фотографии, становится ясно, что страница в эти результаты не включена.
server="8343" farm="9" title="111_8Q1B2033" ispublic="1" isfriend="0" isfamily="0" url_s="https://farm9.staticflickr.com/8343/8232706407_9662732625_m.jpg"
height_s="240" width_s="163" />
Похоже, придется писать новые запросы XML? К счастью, это не так. Обратившись к странице документации Flickr по адресу https://www.flickr.com/services/api/misc.urls.
html
, мы видим, что URL-адреса страниц отдельных фотографий строятся по схеме:
https://www.flickr.com/photos/идентификатор-пользователя/идентификатор-фото
Идентификатор фотографии совпадает со значением атрибута id в разметке XML.
Мы уже сохранили его в поле mId объекта
GalleryItem
. Как насчет идентификатора пользователя? Немного покопавшись в документации, мы находим, что атрибут owner в XML содержит идентификатор пользователя. Таким образом, извлекая атрибут owner
, мы можем построить URL-адрес по атрибутам из XML фотографии:
https://www.flickr.com/photos/owner/id
Чтобы реализовать этот план, включите следующий код в
GalleryItem
31

И еще один блок данных Flickr
509
Листинг 31.1. Добавление кода построения URL страницы фотографии (GalleryItem.java)
public class GalleryItem {
private String mCaption;
private String mId;
private String mUrl;
private String mOwner;
public void setUrl(String url) {
mUrl = url;
}
public String getOwner() {
return mOwner;
}
public void setOwner(String owner) {
mOwner = owner;
}
public String getPhotoPageUrl() {
return "https://www.flickr.com/photos/" + mOwner + "/" + mId;
}
public String toString() {
return mCaption;
}
}
Здесь мы создаем новое свойство mOwner и добавляем короткий метод с именем get-
PhotoPageUrl()
для построения URL-адреса страницы способом, описанным выше.
Теперь изменим метод parseItems(…)
для чтения атрибута owner
Листинг 31.2. Чтение атрибута owner (FlickrFetchr.java)
void parseItems(ArrayList items, XmlPullParser parser) throws XmlPullParserException, IOException {
int eventType = parser.next();
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG &&
XML_PHOTO.equals(parser.getName())) {
String id = parser.getAttributeValue(null, "id");
String caption = parser.getAttributeValue(null, "title");
String smallUrl = parser.getAttributeValue(null, EXTRA_SMALL_URL);
String owner = parser.getAttributeValue(null, "owner");
GalleryItem item = new GalleryItem();
item.setUrl(smallUrl);
item.setOwner(owner);
items.add(item);
}
eventType = parser.next();
}
}
Теперь можно поразвлечься с URL-адресом новой страницы.

510
Глава 31. Просмотр веб-страниц и WebView
Простой способ: неявные интенты
Сначала мы откроем страницу по этому URL-адресу при помощи старого знако- мого — неявного интента. Этот интент запустит браузер с URL-адресом страницы фотографии.
Для начала нужно организовать прослушивание нажатий на элементах представ- ления
GridView
. Это еще одно место, в котором наш код будет слегка отличаться от кода из главы 9 из-за отсутствия подходящей реализации
GridFragment
. Вместо переопределения метода onListItemClick(…)
в фрагменте мы подключим обработ- чик в стиле слушателя щелчков на кнопке, вызывая setOnItemClickListener(…)
в
GridView
После этого остается лишь создать и отправить неявный интент. Добавьте следу- ющий код в
PhotoGalleryFragment
Листинг 31.3. Просмотр веб-страниц с использованием неявных интентов
(PhotoGalleryFragment.java)
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_photo_gallery, container, false);
mGridView = (GridView)v.findViewById(R.id.gridView);
setupAdapter();
mGridView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView gridView, View view, int pos,
long id) {
GalleryItem item = mItems.get(pos);
Uri photoPageUri = Uri.parse(item.getPhotoPageUrl());
Intent i = new Intent(Intent.ACTION_VIEW, photoPageUri);
startActivity(i);
}
});
return v;
}
Запустите приложение PhotoGallery и нажмите на фотографии. На экране нена- долго появляется индикатор прогресса, после чего открывается браузер.
Более сложный способ: WebView
На практике веб-контент чаще требуется отобразить в активности вашего прило- жения вместо перехода в браузер. Допустим, вы хотите отобразить самостоятельно сгенерированную разметку HTML или просто обойтись без браузера. Справочная документация в приложениях часто реализуется в виде веб-страницы, чтобы ее было

Простой способ: неявные интенты
511
удобнее обновлять. Запуск браузера для просмотра справочных страниц выглядит непрофессионально и препятствует изменению поведения, а также интеграции веб-страницы в ваш пользовательский интерфейс.
Для представления веб-контента в пользовательском интерфейсе приложения ис- пользуется класс
WebView
. Мы назвали этот способ «более сложным», но на самом деле он очень прост (хотя по сравнению с неявными интентами все можно назвать сложным).
Нашим первым шагом станет создание новой активности и фрагмента для отобра- жения
WebView
. Начнем, как обычно, с определения файла макета.
Рис. 31.1. Исходный макет (res/layout/fragment_photo_page.xml)
При взгляде на диаграмму возникает мысль: «От
RelativeLayout нет никакой пользы». И верно — однако позднее в этой главе мы наполним его дополнительным
«хромом».
Создайте
PhotoPageFragment как субкласс класса
VisibleFragment
, созданного в предыдущей главе. Необходимо заполнить файл макета, выделить из него
WebView и передать URL-адрес в данных интента.
Листинг 31.4. Создание фрагмента браузера (PhotoPageFragment.java)
package com.bignerdranch.android.photogallery;
public class PhotoPageFragment extends VisibleFragment {
private String mUrl;
private WebView mWebView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
mUrl = getActivity().getIntent().getData().toString();
}
продолжение


512
1   ...   43   44   45   46   47   48   49   50   ...   55

перейти в каталог файлов

Образовательный портал Как узнать результаты егэ Стихи про летний лагерь 3агадки для детей

Образовательный портал Как узнать результаты егэ Стихи про летний лагерь 3агадки для детей