Главная страница
Образовательный портал Как узнать результаты егэ Стихи про летний лагерь 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
страница15 из 55
КаталогОбразовательный портал Как узнать результаты егэ Стихи про летний лагерь 3агадки для детей
Образовательный портал Как узнать результаты егэ Стихи про летний лагерь 3агадки для детей
1   ...   11   12   13   14   15   16   17   18   ...   55
Глава 7. UI-фрагменты и FragmentManager
Найдите макет
CrimeActivity в файле res/layout/activity_crime.xml
. Откройте файл и за- мените макет по умолчанию элементом
FrameLayout
, изображенным на рис. 7.12.
Разметка XML должна совпадать с приведенной в листинге 7.4.
Листинг 7.4. Создание контейнера фрагмента (activity_crime.xml)

android:id="@+id/fragmentContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
Хотя activity_crime.xml состоит исключительно из контейнерного представления одно- го фрагмента, макет активности может быть более сложным; он может определять несколько контейнерных представлений, а также собственные виджеты.
Просмотрите файл макета или запустите CriminalIntent, чтобы проверить свой код.
Вы увидите только пустой элемент
FrameLayout
, потому что
CrimeActivity еще не выполняет функции хоста фрагмента.
Рис. 7.13. Пустой элемент FrameLayout
Позднее мы напишем код, помещающий представление фрагмента в этот элемент
FrameLayout
. Но сначала фрагмент нужно создать.

Хостинг UI-фрагментов
151
Создание UI-фрагмента
Последовательность действий по созданию UI-фрагмента не отличается от после- довательности действий по созданию активности:

построение интерфейса посредством определения виджетов в файле макета;

создание класса и назначение макета, который был определен ранее, его пред- ставлением;

подключение виджетов, заполненных на основании макета в коде.
Определение макета CrimeFragment
Представление
CrimeFragment будет отображать информацию, содержащуюся в эк- земпляре
Crime
. Со временем в классе
Crime и представлении класса
CrimeFragment добавится много интересного, а в этой главе мы ограничимся текстовым полем для хранения заголовка.
На рис. 7.14 изображен макет представления
CrimeFragment
. Он состоит из верти- кального элемента
LinearLayout
, содержащего
EditText
— виджет с областью для ввода и редактирования текста.
Рис. 7.14. Исходный макет CrimeFragment
Чтобы создать файл макета, щелкните правой кнопкой мыши на папке res/layout на панели
Package
Explorer и выберите команду
New

Android
XML
File
. Проследите за тем, чтобы в окне был выбран тип ресурса
Layout
, а файлу фрагмента было присвоено имя fragment_crime.xml
. Выберите корневым элементом
LinearLayout и нажмите кнопку
Finish
Когда файл откроется, перейдите к разметке XML. Мастер уже добавил элемент
LinearLayout за вас. Руководствуясь рис. 7.14, внесите необходимые изменения в fragment_crime.xml
. Проверьте результаты по листингу 7.5.

152
Глава 7. UI-фрагменты и FragmentManager
Листинг 7.5. Файл макета для представления фрагмента (fragment_crime.xml)

android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/crime_title_hint"
/>

Откройте файл res/values/strings.xml
, добавьте строковый ресурс crime_title_hint и уалите лишние строковые ресурсы hello_world и menu_settings
, сгенерирован- ные шаблоном.
Листинг 7.6. Добавление и удаление строк (res/values/strings.xml)


CriminalIntent
Hello world!
Settings
CrimeActivity
Enter a title for the crime.

Сохраните файлы. Удаление строки menu_settings привело к возникновению ошибки в проекте. Чтобы исправить ее, найдите на панели
Package
Explorer файл res/menu/activity_crime.xml
. Этот файл содержит определение меню, сгенерированное шаблоном, содержащее ссылку на строку menu_settings
. Мы не будем использовать этот файл меню для CriminalIntent, поэтому его можно просто удалить с панели
Package
Explorer
Удаление ресурса меню заставляет Eclipse построить приложение заново. Теперь проект должен быть свободен от ошибок. Переключитесь на графический конструк- тор, чтобы просмотреть результат разметки fragment_crime.xml
Создание класса CrimeFragment
Щелкните правой кнопкой мыши на пакете com.bignerdranch.android.criminalintent и выберите команду
New

Class
. Введите имя класса
CrimeFragment и щелкните на кнопке
Browse
, чтобы выбрать суперкласс. В открывшемся окне начинайте вводить строку
Fragment
. Мастер предлагает несколько классов. Выберите класс android.
support.v4.app.Fragment
— класс
Fragment из библиотеки поддержки. Щелкните на кнопке
OK
(Если вы видите несколько версий android.support.v4.app.Fragment
, выберите ту, которая является частью проекта CriminalIntent из
CriminalIntent/libs/
.)

Хостинг UI-фрагментов
153
Рис. 7.15. Выбор класса Fragment из библиотеки поддержки
Реализация методов жизненного цикла фрагмента
CrimeFragment
— контроллер, взаимодействующий с объектами модели и представ- ления. Его задача — выдача подробной информации о конкретном преступлении и ее обновление при модификации пользователем.
В приложении GeoQuiz активности выполняли большую часть работы контрол- лера в методах жизненного цикла. В приложении CriminalIntent эта работа будет выполняться фрагментами в методах жизненного цикла фрагментов. Многие из этих методов соответствуют уже известным вам методам
Activity
, таким как onCreate(Bundle)
В файле
CrimeFragment.java добавьте переменную для экземпляра
Crime и реализацию
Fragment.onCreate(Bundle)
Листинг 7.7. Переопределение Fragment.onCreate(Bundle) (CrimeFragment.java)
public class CrimeFragment extends Fragment {
private Crime mCrime;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mCrime = new Crime();
}
}

154
Глава 7. UI-фрагменты и FragmentManager
В этой реализации стоит обратить внимание на пару моментов. Во-первых, ме- тод
Fragment.onCreate(Bundle)
объявлен открытым, тогда как метод
Activity.
onCreate(Bundle)
объявлен защищенным.
Fragment.onCreate(…)
и другие методы жизненного цикла
Fragment должны быть открытыми, потому что они будут вы- зываться произвольной активностью, которая станет хостом фрагмента.
Во-вторых, как и в случае с активностью, фрагмент использует объект
Bundle для сохранения и загрузки состояния. Вы можете переопределить
Fragment.on-
Save InstanceState(Bundle)
для ваших целей, как и метод
Activity.onSave-
InstanceState(Bundle)
Обратите внимание на то, что не происходит в
Fragment.onCreate(…)
: мы не запол- няем представление фрагмента. Экземпляр фрагмента настраивается в
Fragment.
onCreate(…)
, но создание и настройка представления фрагмента осуществляются в другом методе жизненного цикла фрагмента:
public View onCreateView(LayoutInflater inflater, ViewGroup parent,
Bundle savedInstanceState)
Именно в этом методе заполняется макет представления фрагмента, а заполненный объект
View возвращает активность хосту. Параметры
LayoutInflater и
ViewGroup необходимы для заполнения макета. Объект
Bundle содержит данные, которые ис- пользуются методом для воссоздания представления по сохраненному состоянию.
В файле
CrimeFragment.java добавьте реализацию onCreateView(…)
, которая заполняет разметку fragment_crime.xml
Листинг 7.8. Переопределение onCreateView(…) (CrimeFragment.java)
public class CrimeFragment extends Fragment {
private Crime mCrime;
@Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mCrime = new Crime();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_crime, parent, false);
return v;
}
}
В методе onCreateView(…)
мы явно заполняем представление фрагмента, вызывая
LayoutInflater.inflate(…)
с передачей идентификатора ресурса макета. Второй па- раметр определяет родителя представления, что обычно необходимо для правильной настройки виджета. Третий параметр указывает, нужно ли включать заполненное представление в родителя. Мы передаем false
, потому что представление будет добавлено в коде активности.

Хостинг UI-фрагментов
155
Подключение виджетов в фрагменте
В методе onCreateView(…)
также настраивается реакция виджета
EditText на ввод пользователя. После того как представление будет заполнено, метод получает ссылку на
EditText и добавляет слушателя.
Листинг 7.9. Настройка виджета EditText (CrimeFragment.java)
public class CrimeFragment extends Fragment {
private Crime mCrime;
private EditText mTitleField;
@Override public View onCreateView(LayoutInflater inflater, ViewGroup parent,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_crime, parent, false);
mTitleField = (EditText)v.findViewById(R.id.crime_title);
mTitleField.addTextChangedListener(new TextWatcher() {
public void onTextChanged(
CharSequence c, int start, int before, int count) {
mCrime.setTitle(c.toString());
}
public void beforeTextChanged(
CharSequence c, int start, int count, int after) {
// Здесь намеренно оставлено пустое место
}
public void afterTextChanged(Editable c) {
// И здесь тоже
}
});
return v;
}
}
Получение ссылок в
Fragment.onCreateView(…)
происходит практически так же, как в
Activity.onCreate(…)
. Единственное различие заключается в том, что для пред- ставления фрагмента вызывается метод
View.findViewById(int)
. Метод
Activity.
findViewById(int)
, который мы использовали ранее, является вспомогательным методом, который вызывает
View.findViewById(int)
в своей внутренней реализации.
У класса
Fragment аналогичного вспомогательного метода нет, поэтому приходится вызывать основной метод.
Назначение слушателей в фрагменте работает точно так же, как в активности. В ли- стинге 7.9 мы создаем анонимный класс, который реализует интерфейс слушателя
TextWatcher
. Этот интерфейс содержит три метода, но нас интересует только один: onTextChanged(…)
В методе onTextChanged(…)
мы вызываем toString()
для объекта
CharSequence
, представляющего ввод пользователя. Этот метод возвращает строку, которая затем используется для задания заголовка
Crime

156
Глава 7. UI-фрагменты и FragmentManager
Код
CrimeFragment готов. Было бы замечательно, если бы вы могли запустить
CriminalIntent и поэкспериментировать с написанным кодом. К сожалению, это невозможно — фрагменты не могут выводить свои представления на экран.
Чтобы реализовать задуманное, необходимо сначала добавить
CrimeFragment в
CrimeActivity
Добавление UI-фрагмента в FragmentManager
Когда в Honeycomb появился класс
Fragment
, в класс
Activity были внесены изменения: в него был добавлен компонент, называемый
FragmentManager
. Он от- вечает за управление фрагментами и добавление их представлений в иерархию представлений активности.
FragmentManager управляет двумя структурами: списком фрагментов и стеком транзакций фрагментов (о котором я вскоре расскажу).
Фрагменты
Стек транзакций
Рис. 7.16. FragmentManager
В приложении CriminalIntent нас интересует только список фрагментов
Fragment-
Manager
Чтобы добавить фрагмент в активность в коде, следует обратиться с вызовом к объ- екту
FragmentManager активности.
Прежде всего необходимо получить сам объект
FragmentManager
. В
CrimeActivity.java включите следующий код в onCreate(…)
Листинг 7.10. Получение объекта FragmentManager (CrimeActivity.java)
public class CrimeActivity extends FragmentActivity {
/** Вызывается при создании активности. */
@Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_crime);
FragmentManager fm = getSupportFragmentManager();
}
}

Хостинг UI-фрагментов
157
Мы вызываем getSupportFragmentManager()
, потому что в приложении используется библиотека поддержки и класс
FragmentActivity
. Если бы нас не интересовала со- вместимость с устройствами, предшествующими Honeycomb, то вместо этого можно было бы субклассировать
Activity и вызвать getFragmentManager()
Транзакции фрагментов
После получения объекта
FragmentManager добавьте следующий код, который передает ему фрагмент для управления. (Позднее мы рассмотрим этот код более подробно, а пока просто включите его в приложение.)
Листинг 7.11. Добавление CrimeFragment (CrimeActivity.java)
public class CrimeActivity extends FragmentActivity {
/** Вызывается при создании активности. */
@Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_crime);
FragmentManager fm = getSupportFragmentManager();
Fragment fragment = fm.findFragmentById(R.id.fragmentContainer);
if (fragment == null) {
fragment = new CrimeFragment();
fm.beginTransaction()
.add(R.id.fragmentContainer, fragment)
.commit();
}
}
}
Разбираться в коде, добавленном в листинге 7.11, лучше всего не с начала. Найдите операцию add(…)
и окружающий ее код. Этот код создает и закрепляет транзакцию
фрагмента
Листинг 7.12. Транзакция фрагмента (CrimeActivity.java)
if (fragment == null) {
fragment = new CrimeFragment();
fm.beginTransaction()
.add(R.id.fragmentContainer, fragment)
.commit();
Транзакции фрагментов используются для добавления, удаления, присоединения, отсоединения и замены фрагментов в списке фрагментов. Они лежат в основе ме- ханизма использования фрагментов для формирования и модификации экранов во время выполнения.
FragmentManager ведет стек транзакций, по которому вы можете перемещаться.
Метод
FragmentManager.beginTransaction()
создает и возвращает экзем- пляр
FragmentTransaction
. Класс
FragmentTransaction использует динамич- ный интерфейс — методы, настраивающие
FragmentTransaction
, возвращают

158
Глава 7. UI-фрагменты и FragmentManager
FragmentTransaction вместо void
, что позволяет объединять их вызовы в цепочку.
Таким образом, выделенный код в листинге 7.12 означает: «Создать новую тран- закцию фрагмента, включить в нее одну операцию add
, а затем закрепить».
Метод add(…)
является основным содержанием транзакции. Он получает два параметра: идентификатор контейнерного представления и недавно созданный объект
CrimeFragment
. Идентификатор контейнерного представления вам должен быть знаком: это идентификатор ресурса элемента
FrameLayout
, определенного в файле activity_crime.xml
. Идентификатор контейнерного представления выполняет две функции:

Он сообщает
FragmentManager
, где в представлении активности должно нахо- диться представление фрагмента.

Он обеспечивает однозначную идентификацию фрагмента в списке
Fragment-
Manager
Когда вам потребуется получить экземпляр
CrimeFragment от
FragmentManager
, за- просите его по идентификатору контейнерного представления.
Листинг 7.13. Получение существующего фрагмента по идентификатору контейнерного представления (CrimeActivity.java)
FragmentManager fm = getSupportFragmentManager();
Fragment fragment = fm.findFragmentById(R.id.fragmentContainer);
if (fragment == null) {
fragment = new CrimeFragment();
fm.beginTransaction()
.add(R.id.fragmentContainer, fragment)
.commit();
}
Может показаться странным, что
FragmentManager идентифицирует
CrimeFragment по идентификатору ресурса
FrameLayout
. Однако идентификация UI-фрагмента по идентификатору ресурса его контейнерного представления встроена в механизм работы
FragmentManager
Теперь мы можем кратко описать код, добавленный в листинг 7.11, от начала до конца.
Сначала мы запрашиваем у
FragmentManager фрагмент с идентификатором контей- нерного представления
R.id.fragmentContainer
. Если этот фрагмент уже находится в списке,
FragmentManager возвращает его.
Почему фрагмент может уже находиться в списке? Вызов
CrimeActivity.onCre- ate(…)
может быть выполнен в ответ на воссоздание объекта
CrimeActivity после его уничтожения из-за поворота или освобождения памяти. При уничтожении активности ее экземпляр
FragmentManager сохраняет список фрагментов. При вос- создании активности новый экземпляр
FragmentManager загружает список и вос- создает хранящиеся в нем фрагменты, чтобы все работало, как прежде.
С другой стороны, если фрагменты с заданным идентификатором контейнерно- го представления отсутствуют, значение fragment равно null
. В этом случае мы

Хостинг UI-фрагментов
159
создаем новый экземпляр
CrimeFragment и новую транзакцию, которая добавляет фрагмент в список.
Теперь
CrimeActivity является хостом для
CrimeFragment
. Чтобы убедиться в этом, запустите приложение CriminalIntent. На экране отображается представление, определенное в файле fragment_crime.xml
(рис. 7.17).
Рис. 7.17. CrimeActivity является хостом представления CrimeFragment
Возможно, один виджет на экране выглядит не таким уж большим достижением для всей работы, проделанной в этой главе. Однако мы заложили прочный фун- дамент для более серьезных задач, которые нам придется решать в приложении
CriminalIntent в последующих главах.
FragmentManager и жизненный цикл фрагмента
После знакомства с
FragmentManager стоит еще раз вернуться к жизненному циклу фрагмента.
Объект
FragmentManager активности отвечает за вызов методов жизненного цикла фрагментов в списке. Методы onAttach(Activity)
, onCreate(Bundle)
и onCreateV- iew(…)
вызываются при добавлении фрагмента в
FragmentManager
Метод onActivityCreated(…)
вызывается после выполенния метода onCreate(…)
активности-хоста. Мы добавляем
CrimeFragment в
CrimeActivity.onCreate(…)
, так что этот метод будет вызван после добавления фрагмента.

160
1   ...   11   12   13   14   15   16   17   18   ...   55

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

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

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