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

Программирование под 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
страница34 из 55
КаталогОбразовательный портал Как узнать результаты егэ Стихи про летний лагерь 3агадки для детей
Образовательный портал Как узнать результаты егэ Стихи про летний лагерь 3агадки для детей
1   ...   30   31   32   33   34   35   36   37   ...   55
Глава 21. Неявные интенты
Проверка реагирующих активностей
На два неявных интента, созданных в этой главе, кто-то гарантированно отреагирует.
На устройстве Android заведомо присутствует то или иное приложение для работы с электронной почтой и контактное приложение. А если вы создаете другой неявный интент для устройства, на котором может не оказаться подходящих активностей?
Если ОС не найдет подходящую активность, в приложении происходит сбой.
Проблема решается предварительной проверкой того, от какой части ОС поступил вызов
PackageManager
. Код выглядит примерно так:
PackageManager pm = getPackageManager();
List activities = pm.queryIntentActivities(yourIntent, 0);
boolean isIntentSafe = activities.size() > 0;
Интент передается методу queryIntentActivities(…)
класса
PackageManager
. Метод возвращает список объектов, содержащих метаданные об активностях, отреаги- ровавших на переданный интент. Остается убедиться в том, что список содержит хотя бы один элемент — то есть на устройстве имеется хотя бы одна активность, реагирующая на интент.
Выполнение этой проверки в onCreateView(…)
позволяет отключить варианты, на которые устройство не сможет отреагировать.
Упражнение. Другой неявный интент
Возможно, вместо отправки отчета разгневанный пользователь предпочтет разо- браться с подозреваемым по телефону. Добавим новую кнопку для звонка указан- ному подозреваемому.
Нам понадобится извлечь из базы данных контактов телефонный номер, после чего можно создать неявный интент с URI телефона:
Uri number = Uri.parse("tel:5551234");
При этом может использоваться действие
Intent.ACTION_DIAL
или
Intent.ACTION_
CALL
ACTION_CALL
запускает телефонное приложение и немедленно осуществляет звонок по номеру, отправленному в интенте;
ACTION_DIAL
только вводит номер и ждет, пока пользователь инициирует звонок.
Мы рекомендуем использовать
ACTION_DIAL
. Режим
ACTION_CALL
может быть ограни- чен, и для него определенно потребуются разрешения. Кроме того, у пользователя будет возможность немного остыть перед нажатием кнопки вызова.

Двухпанельные
интерфейсы
В этой главе мы создадим для CriminalIntent планшетный интерфейс, в котором пользователь может одновременно видеть и взаимодействовать со списком престу- плений и подробным описанием конкретного преступления. На рис. 22.1 изображен такой интерфейс типа «список-детализация».
Рис. 22.1. Главное и детализированное представления одновременно находятся на экране
22

368
Глава 22. Двухпанельные интерфейсы
Для тестирования программ этой главы вам понадобится планшетное устрой- ство или AVD. Чтобы создать виртуальный планшет AVD, выполните команду
Window

Android
Virtual
Device
Manager
. Выполните команду
New и выберите в качестве устройства (
Device
) AVD один из двух вариантов, выделенных на рис. 22.2. Затем задайте для AVD целевой API уровня 17.
Рис. 22.2. Выбор устройства для планшетного AVD
Гибкость макета
На телефоне активность
CrimeListActivity должна заполнять однопанельный макет, как она делает в настоящее время. На планшете она должна заполнять двух- панельный макет, способный одновременно отображать главное и детализированное представления.
В двухпанельном макете
CrimeListActivity будет отображать как
CrimeListFrag- ment
, так и
CrimeFragment
, как показано на рис. 22.3.
Детали- зация
Телефон
Планшет
Список
Детализация
Список
Рис. 22.3. Разновидности макетов

Модификация SingleFragmentActivity
369
Для этого необходимо:

изменить
SingleFragmentActivity
, чтобы выбор заполняемого макета не был жестко фиксирован в программе;

создать новый макет, состоящий из двух контейнеров фрагментов;

изменить
CrimeListActivity
, чтобы на телефонах заполнялся однопанельный макет, а на планшетах — двухпанельный.
Модификация SingleFragmentActivity
CrimeListActivity является субклассом
SingleFragmentActivity
. В настоящее время класс
SingleFragmentActivity настроен таким образом, чтобы он всегда заполнял activity_fragment.xml
Чтобы класс
SingleFragmentActivity стал более гибким, мы сделаем так, чтобы субкласс мог предоставлять свой идентификатор ресурса макета.
В файле
SingleFragmentActivity.java добавьте защищенный метод, который возвращает идентификатор макета, заполняемого активностью.
Листинг 22.1. Обеспечение гибкости SingleFragmentActivity (SingleFragmentActivity.java)
public abstract class SingleFragmentActivity extends FragmentActivity {
protected abstract Fragment createFragment();
protected int getLayoutResId() {
return R.layout.activity_fragment;
}
@Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragment);
setContentView(getLayoutResId());
FragmentManager fm = getSupportFragmentManager();
Fragment fragment = fm.findFragmentById(R.id.fragmentContainer);
if (fragment == null) {
fragment = createFragment();
fm.beginTransaction()
.add(R.id.fragmentContainer, fragment)
.commit();
}
}
}
Реализация класса
SingleFragmentActivity по умолчанию будет работать так же, как прежде, но теперь его субклассы могут переопределить getLayoutResId()
для возвращения макета, отличного от activity_fragment.xml

370
Глава 22. Двухпанельные интерфейсы
Создание макета с двумя
контейнерами фрагментов
На панели
Package
Explorer щелкните правой кнопкой мыши на каталоге res/layout/
и создайте новый файл Android в формате XML. Убедитесь в том, что для файла выбран тип ресурса
Layout
, присвойте файлу имя activity_twopane.xml и назначьте его корневым элементом
LinearLayout
Напишите разметку XML для двухпанельного макета, изображенного на рис. 22.4.
Рис. 22.4. Макет с двумя контейнерами фрагментов (layout/activity_twopane.xml)
Обратите внимание: у первого виджета
FrameLayout задан идентификатор маке- та fragmentContainer
, поэтому код
SingleFragmentActivity.onCreate(…)
может работать так же, как прежде. При создании активности фрагмент, возвращаемый createFragment()
, появится на левой панели.
Протестируйте макет в
CrimeListActivity
; для этого переопределите метод get-
LayoutResId()
так, чтобы он возвращал
R.layout.activity_twopane
Листинг 22.2. Переход к файлу двухпанельного макета (CrimeListActivity.java)
public class CrimeListActivity extends SingleFragmentActivity {
@Override protected Fragment createFragment() {
return new CrimeListFragment();
}
@Override
protected int getLayoutResId() {
return R.layout.activity_twopane;
}
}
Запустите приложение CriminalIntent на планшетном устройстве и убедитесь в том, что на экране отображаются две панели (рис. 22.5). Большая панель детализации

Создание макета с двумя контейнерами фрагментов
371
пуста, а нажатие на элементе списка не отображает подробную информацию о пре- ступлении. Контейнер детализированного представления будет подключен позднее в этой главе.
Рис. 22.5. Двухпанельный макет на планшете
В своей текущей версии
CrimeListActivity также заполняет двухпанельный интер- фейс при запуске на телефоне. В следующем разделе мы исправим этот недостаток при помощи ресурса-псевдонима.
Использование ресурса-псевдонима
Ресурс-псевдоним
(alias resource) представляет собой ресурс, указывающий на дру- гой ресурс. Ресурсы-псевдонимы находятся в каталоге res/values/
и по умолчанию определяются в файле refs.xml
В этом разделе мы создадим ресурс-псевдоним, который на телефонах ссылается на макет activity_fragment.xml
, и на планшетах — на макет activity_twopane.xml
На панели
Package
Explorer щелкните правой кнопкой мыши на каталоге res/layout/
и создайте новый файл Android в формате XML. Убедитесь в том, что для файла выбран тип ресурса
Values
, присвойте файлу имя refs.xml
, назначьте его корневым элементом resources и щелкните на кнопке
Finish
. Затем добавьте элемент, при- веденный в листинге 22.3.
Листинг 22.3. Создание значения по умолчанию для ресурса-псевдонима (res/values/refs.xml)

@layout/activity_fragment

Значение ресурса представляет собой ссылку на однопанельный макет. Ресурс также обладает идентификатором:
R.layout.activity_masterdetail
. Обратите внимание:

372
Глава 22. Двухпанельные интерфейсы внутренний класс идентификатора определяется атрибутом type псевдонима. И хотя сам псевдоним находится в res/values/
, его идентификатор хранится в
R.layout
Теперь этот идентификатор ресурса может использоваться вместо
R.layout.activi- ty_fragment
. Внесите следующее изменение в
CrimeListActivity
Листинг 22.4. Повторная замена макета (CrimeListActivity.java)
@Override protected int getLayoutResId() {
return R.layout.activity_twopane;
return R.layout.activity_masterdetail;
}
Запустите приложение CriminalIntent и убедитесь в том, что псевдоним работает правильно. Активность
CrimeListActivity снова должна заполнять однопанельный макет.
Создание альтернативы для планшета
Так как псевдоним находится в res/values/
, он используется по умолчанию. Следо- вательно, по умолчанию
CrimeListActivity заполняет однопанельный макет.
Теперь мы создадим альтернативный ресурс, чтобы псевдоним activity_masterdetail на планшетных устройствах ссылался на activity_twopane.xml
На панели
Package
Explorer щелкните правой кнопкой мыши на каталоге res/
и соз- дайте новую папку с именем values-sw600dp
. Скопируйте файл res/values/refs.xml в res/
values-sw600dp/
и измените макет, на который ссылается псевдоним.
Листинг 22.5. Альтернативный псевдоним для планшетных устройств
(res/values-sw600dp/refs.xml)

@layout/activity_fragment
@layout/activity_twopane

Что означает конфигурационный квалификатор
-sw600dp
? Сокращение «sw» происходит от «Smallest Width» (наименьшая ширина), но относится к меньшему размеру экрана, а следовательно, не зависит от текущей ориентации устройства.
Используя квалификатор
-sw600dp
, вы указываете: «Этот ресурс должен использо- ваться на любых устройствах, у которых меньший размер составляет 600dp и выше».
Это хороший критерий для определения экранов планшетных устройств.
И еще одно: квалификатор sw появился в Android 3.2. Это означает, что планшетное устройство с Android 3.0 и 3.1 его не опознает. Для решения этой проблемы можно добавить еще один альтернативный ресурс, использующий устаревший квалифи- катор размера экрана
-xlarge
Щелкните правой кнопкой мыши на каталоге res/
и создайте новую папку с именем values-xlarge
. Скопируйте файл res/values-sw600dp/refs.xml в res/values-xlarge/
. Теперь

Активность: управление фрагментами
373
у вас имеется другой альтернативный ресурс, который выглядит так, как показано в листинге 22.6.
Листинг 22.6. Альтернативный псевдоним для планшетных устройств до версии 3.2
(res/values-xlarge/refs.xml)

@layout/activity_twopane

Квалификатор
-xlarge содержит ресурсы для устройств с минимальными разме- рами 720 × 960dp. Он будет использоваться только устройствами с версией, пред- шествующей Android 3.2. Более поздние версии обнаружат и используют
-sw600dp
Запустите приложение CriminalIntent на телефоне и планшете. Убедитесь в том, что одно- и двухпанельные макеты отображаются там, где предполагалось.
Активность: управление фрагментами
Итак, макеты ведут себя так, как положено, и мы можем перейти к добавлению
CrimeFragment в контейнер фрагмента детализации при использовании двухпа- нельного макета
CrimeListActivity
На первый взгляд кажется, что для этого достаточно написать альтернативную реализацию
CrimeListFragment.onListItemClick(…)
для планшетов. Вместо за- пуска нового экземпляра
CrimePagerActivity метод onListItemClick(…)
получает экземпляр
FragmentManager
, принадлежащий
CrimeListActivity
, и закрепляет транзакцию, которая добавляет
CrimeFragment в контейнер фрагмента детализации.
Код выглядит примерно так:
public void onListItemClick(ListView l, View v, int position, long id) {
// Получение экземпляра Crime от адаптера
Crime crime = ((CrimeAdapter)getListAdapter()).getItem(position);
// Включение нового экземпляра CrimeFragment в макете активности
Fragment fragment = CrimeFragment.newInstance(crime.getId());
FragmentManager fm = getActivity().getSupportFragmentManager();
fm.beginTransaction()
.add(R.id.detailFragmentContainer, fragment)
.commit();
}
Такое решение работает, но оно противоречит хорошему стилю программирова- ния Android. Предполагается, что фрагменты представляют собой автономные компонуемые блоки. Если написанный вами фрагмент добавляет фрагменты в
FragmentManager активности, значит, он делает допущения относительно того, как работает активность-хост, и перестает быть автономным компонуемым блоком.
Например, в приведенном выше коде
CrimeListFragment добавляет
CrimeFragment в
CrimeListActivity и предполагает, что в макете
CrimeListActivity присутству- ет контейнер detailFragmentContainer
. Такими вопросами должна заниматься активность-хост
CrimeListFragment
, а не
CrimeListFragment

374
Глава 22. Двухпанельные интерфейсы
Для сохранения независимости фрагментов мы делегируем выполнение работы активности-хосту, определяя интерфейсы обратного вызова в ваших фрагментах.
Активности-хосты реализуют эти интерфейсы для выполнения операций по управ- лению фрагментами и обеспечения макетно-зависимого поведения.
Интерфейсы обратного вызова фрагментов
Чтобы делегировать функциональность активности-хосту, фрагмент обычно опреде- ляет интерфейс обратного вызова с именем
Callbacks
. Этот интерфейс определяет работу, которая должна быть выполнена для фрагмента его «начальником» — ак- тивностью-хостом. Любая активность, выполняющая функции хоста фрагментов, должна реализовать этот интерфейс.
С интерфейсом обратного вызова фрагмент может вызывать методы активности- хоста, не располагая никакой информацией о ней.
Реализация CrimeListFragment.Callbacks
Чтобы реализовать интерфейс
Callbacks
, следует сначала определить переменную для хранения объекта, реализующего
Callbacks
. Затем активность-хост преобра- зуется к
Callbacks
, а результат присваивается этой переменной.
Активность назначается в методе жизненного цикла
Fragment
:
public void onAttach(Activity activity)
Этот метод вызывается при присоединении фрагмента к активности (независимо от того, было он сохранен или нет). Аналогичным образом переменной присваивается null в соответствующем завершающем методе жизненного цикла:
public void onDetach()
Переменной присваивается null
, потому что в дальнейшем вы не сможете обратить- ся к активности или рассчитывать на то, что активность продолжит существовать.
В файле
CrimeListFragment.java включите в класс
CrimeListFragment интерфейс
Call backs
. Также добавьте переменную mCallbacks и переопределите методы onAttach(Activity)
и onDetach()
, в которых задается и сбрасывается ее значение.
Листинг 22.7. Добавление интерфейса обратного вызова (CrimeListFragment.java)
public class CrimeListFragment extends ListFragment {
private ArrayList mCrimes;
private boolean mSubtitleVisible;
private Callbacks mCallbacks;
/**
* Обязательный интерфейс для активности-хоста.
*/
public interface Callbacks {
void onCrimeSelected(Crime crime);
}
@Override

Активность: управление фрагментами
375
public void onAttach(Activity activity) {
super.onAttach(activity);
mCallbacks = (Callbacks)activity;
}
@Override
public void onDetach() {
super.onDetach();
mCallbacks = null;
}
Теперь у
CrimeListFragment имеется механизм вызова методов активности-хоста. Не- важно, какая активность является хостом — если она реализует
CrimeListFragment.
Callbacks
, внутренняя реализация
CrimeListFragment будет работать одинаково.
Обратите внимание на то, как
CrimeListFragment выполняет непроверяемое пре- образование своей активности к
CrimeListFragment.Callbacks
. Это означает, что активность-хост должна реализовать
CrimeListFragment.Callbacks
. В самой за- висимости нет ничего плохого, но ее важно документировать.
Затем в классе
CrimeListActivity реализуйте
CrimeListFragment.Callbacks
. Метод onCrimeSelected(Crime)
пока оставьте пустым.
Листинг 22.8. Реализация обратных вызовов (CrimeListActivity.java)
public class CrimeListActivity extends SingleFragmentActivity
implements CrimeListFragment.Callbacks {
@Override protected Fragment createFragment() {
return new CrimeListFragment();
}
@Override protected int getLayoutResId() {
return R.layout.activity_twopane;
}
public void onCrimeSelected(Crime crime) {
}
}
CrimeListFragment будет вызывать этот метод onListItemClick(…)
, а также тогда, когда пользователь выбирает команду создания новой записи преступления. Для начала нужно понять, как должна быть устроена реализация
CrimeListActivity.
onCrimeSelected(Crime)
При вызове onCrimeSelected(Crime)
класс
CrimeListActivity должен выполнить одну из двух операций:

если используется телефонный интерфейс — запустить новый экземпляр
CrimePagerActivity
;

если используется планшетный интерфейс — поместить
CrimeFragment в detailFragmentContainer

376
1   ...   30   31   32   33   34   35   36   37   ...   55

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