Главная страница
Образовательный портал Как узнать результаты егэ Стихи про летний лагерь 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
страница20 из 55
КаталогОбразовательный портал Как узнать результаты егэ Стихи про летний лагерь 3агадки для детей
Образовательный портал Как узнать результаты егэ Стихи про летний лагерь 3агадки для детей
1   ...   16   17   18   19   20   21   22   23   ...   55
Глава 10. Аргументы фрагментов
Получение аргументов
Когда фрагменту требуется получить доступ к его аргументам, он вызывает метод getArguments()
класса
Fragment
, а затем один из get
-методов
Bundle для конкрет- ного типа.
В методе
CrimeFragment.onCreate(…)
замените код упрощенного решения выборкой
UUID из аргументов фрагмента.
Листинг 10.7. Получение идентификатора преступления из аргументов (CrimeFragment.java)
@Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
UUID crimeId = (UUID)getActivity().getIntent()
.getSerializableExtra(EXTRA_CRIME_ID);
UUID crimeId = (UUID)getArguments().getSerializable(EXTRA_CRIME_ID);
mCrime = CrimeLab.get(getActivity()).getCrime(crimeId);
}
Запустите приложение CriminalIntent. Оно работает точно так же, но архитектура с независимостью
CrimeFragment должна вызвать у вас приятные чувства. Кроме того, она хорошо подготовит нас к следующей главе, в которой мы реализуем более сложную систему навигации в CriminalIntent.
Перезагрузка списка
Осталась еще одна подробность, которой нужно уделить внимание. Запустите приложение CriminalIntent, щелкните на элементе списка и внесите изменения в подробную информацию о преступлении. Эти изменения сохраняются в модели, но при возвращении к списку представление остается неизменным.
Мы должны сообщить адаптеру спискового представления, что набор данных из- менился (или мог измениться), чтобы тот мог заново получить данные и повторно загрузить список. Работая со стеком возврата
ActivityManager
, можно перезагрузить список в нужный момент.
Когда
CrimeListFragment запускает экземпляр
CrimeActivity
, последний помещается на вершину стека. При этом экземпляр
CrimeActivity
, который до этого находился на вершине, приостанавливается и останавливается.
Когда пользователь нажимает кнопку
Back для возвращения к списку, экземпляр
CrimeActivity извлекается из стека и уничтожается. В этот момент
CrimeListAc- tivity запускается и продолжает выполнение.
Когда экземпляр
CrimeListActivity продолжает выполнение, он получает вызов onResume()
от ОС. При получении этого вызова
CrimeListActivity его экземпляр
FragmentManager вызывает onResume()
для фрагментов, хостом которых в настоящее

Запуск активности из фрагмента
209
время является активность. В нашем случае это единственный фрагмент
CrimeList-
Fragment
Нажатие кнопки Back
Нажатие на строке
Рис. 10.4. Стек возврата CriminalIntent
В классе
CrimeListFragment переопределите onResume()
для перезагрузки списка.
Листинг 10.8. Перезагрузка списка в onResume() (CrimeListFragment.java)
@Override
public void onResume() {
super.onResume();
((CrimeAdapter)getListAdapter()).notifyDataSetChanged();
}
Почему для обновления спискового представления переопределяется метод onResume()
, а не onStart()
? Мы не можем предполагать, что активность останав- ливается при нахождении перед ней другой активности. Если другая активность прозрачна, ваша активность может быть только приостановлена. Если же ваша активность приостановлена, а код обновления находится в onStart()
, список не будет перезагружаться. В общем случае самым безопасным местом для выпол- нения действий, связанных с обновлением представления фрагмента, является метод onResume()
Запустите приложение CriminalIntent. Выберите преступление в списке и измените его подробную информацию. Вернувшись к списку, вы немедленно увидите свои изменения.
За последние две главы приложение CriminalIntent серьезно продвинулось вперед.
Давайте взглянем на обновленную диаграмму объектов.

210
Глава 10. Аргументы фрагментов
Контроллер
Модель
Представ- ление
Рис. 10.5. Обновленная диаграмма объектов CriminalIntent
Получение результата
с использованием фрагментов
В этой главе нам не требовалось, чтобы запущенная активность возвращала резуль- тат. А если бы это было нужно? Код выглядел бы почти так же, как в приложении
GeoQuiz. Вместо метода startActivityForResult(…)
класса
Activity использовался бы метод
Fragment.startActivityForResult(…)
. Вместо
Activity.onActivityRe- sult(…)
мы переопределим
Fragment.onActivityResult(…)
public class CrimeListFragment extends ListFragment {
private static final int REQUEST_CRIME = 1;
public void onListItemClick(ListView l, View v, int position, long id) {
// Получение объекта Crime от адаптера
Crime c = ((CrimeAdapter)getListAdapter()).getItem(position);
Log.d(TAG, c.getTitle() + " was clicked");
// Запуск CrimeActivity
Intent i = new Intent(getActivity(), CrimeActivity.class);
startActivityForResult(i, REQUEST_CRIME);
}

Получение результата с использованием фрагментов
211
@Override public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CRIME) {
// Обработка результата
}
}
}
Метод
Fragment.startActivityForResult(Intent,int)
похож на одноименный метод класса
Activity
. Он включает дополнительный код передачи результата вашему фрагменту от активности-хоста.
Возвращение результата от фрагмента выглядит немного иначе. Фрагмент может получить результат от активности, но не может вернуть собственный результат — на это способны только активности. Таким образом, хотя
Fragment содержит методы startActivityForResult(…)
и onActivityResult(…)
, у него нет методов setResult(…)
Вместо этого вы приказываете активности-хосту вернуть значение; вот как это делается:
public class CrimeFragment extends Fragment {
public void returnResult() {
getActivity().setResult(Activity.RESULT_OK, null);
}
}
Возможность возвращения результата активности из фрагмента для приложения
CriminalIntent продемонстрирована в главе 20.

ViewPager
В этой главе мы создадим новую активность, которая станет хостом для
Crime-
Fragment
. Макет активности будет состоять из экземпляра
ViewPager
. Включение виджета
ViewPager в пользовательский интерфейс позволяет «листать» элементы списка, проводя пальцем по экрану.
Справа налево
Слева направо
Рис. 11.1. Листание страниц
На рис. 11.2 представлена обновленная диаграмма CriminalIntent. Новая актив- ность с именем
CrimePagerActivity займет место
CrimeActivity
. Ее макет состоит из экземпляра
ViewPager
Все новые объекты, которые необходимо создать, находятся в пунктирном пря- моугольнике на приведенной диаграмме. Для реализации листания страничных представлений в CriminalIntent ничего другого менять не придется. В частности, класс
CrimeFragment останется неизменным благодаря той работе по обеспечению независимости
CrimeFragment
, которую мы проделали в главе 10.
11

Создание CrimePagerActivity
213
Представ- ление
Модель
Контроллер
Рис. 11.2. Диаграмма макета CrimePagerActivity
В этой главе нам предстоит:

создать класс
CrimePagerActivity
;

определить иерархию представлений, состоящую из
ViewPager
;

связать экземпляр
ViewPager с его адаптером
CrimePagerActivity
;

изменить метод
CrimeListFragment.onListItemClick(…)
так, чтобы он запускал
CrimePagerActivity вместо
CrimeActivity
Создание CrimePagerActivity
Класс
CrimePagerActivity будет субклассом
FragmentActivity
. Он создает и управ- ляет экземпляром
ViewPager
Создайте новый класс с именем
CrimePagerActivity
. Назначьте его суперклассом
FragmentActivity
. В методе onCreate(Bundle)
просто включите сквозной вызов суперкласса — создание экземпляра
ViewPager будет рассмотрено чуть позднее.
Листинг 11.1. Создание ViewPager (CrimePagerActivity.java)
public class CrimePagerActivity extends FragmentActivity {
private ViewPager mViewPager;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}

214
Глава 11. ViewPager
Формирование макетов представлений в коде
В этой книге макеты представлений определяются исключительно в XML-файлах макетов. Обычно это хорошая идея, но в Android нет ничего, что бы заставляло вас определять макеты именно таким образом. Иерархия представлений в этой главе проста — она состоит из единственного представления. По этой причине вместо файла XML мы определим иерархию в программном коде. Так как в макете исполь- зуется всего одно представление, эта задача будет решаться относительно просто.
Создание представления не требует никакого волшебства; просто вызовите его конструктор. К сожалению, полностью изолироваться от XML вам не удастся.
Для некоторых компонентов все равно понадобятся идентификаторы ресурсов;
ViewPager входит в их число.
FragmentManager требует, чтобы любое представление, использованное как контейнер фрагмента, обязательно имело идентификатор.
ViewPager является контейнером фрагмента, поэтому ему необходимо присвоить идентификатор.
С учетом этого мы должны:

создать идентификатор ресурса для
ViewPager
;

создать экземпляр
ViewPager и присвоить его mViewPager
;

настроить его, присвоив ему идентификатор ресурса;

назначить
ViewPager представлением содержимого активности.
Автономные идентификаторы ресурсов
Определение автономного идентификатора ресурса отчасти напоминает опреде- ление строкового ресурса: вы создаете элемент в файле XML из каталога res/values
Создайте новый файл ресурсов Android в формате XML с именем res/values/ids.xml для хранения идентификаторов и добавьте в него идентификатор с именем viewPager
Листинг 11.2. Создание автономного идентификатора ресурса (res/values/ids.xml)




После того как идентификатор будет создан, можно переходить к созданию и ото- бражению
ViewPager
. Создайте экземпляр
ViewPager и назначьте его представлением содержимого.
Листинг 11.3. Программное создание представления содержимого (CrimePagerActivity.java)
@Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mViewPager = new ViewPager(this);
mViewPager.setId(R.id.viewPager);
setContentView(mViewPager);
}

Формирование макетов представлений в коде
215
Класс
ViewPager находится в библиотеке поддержки. В отличие от
Fragment класс
ViewPager доступен только в библиотеке поддержки; в последующих SDK не су- ществует «стандартного» класса
ViewPager
ViewPager и PagerAdapter
Класс
ViewPager в чем-то похож на
AdapterView
(суперкласс
ListView
). Чтобы класс
AdapterView мог выдавать представления, ему необходим экземпляр
Adapter
. Классу
ViewPager необходим адаптер
PagerAdapter
Однако взаимодействие между
ViewPager и
PagerAdapter намного сложнее вза- имодействия между
AdapterView и
Adapter
. К счастью, мы можем использовать
FragmentStatePagerAdapter
— субкласс
PagerAdapter
, который берет на себя многие технические подробности.
FragmentStatePagerAdapter сводит взаимодействие к двум простым методам: get-
Count()
и getItem(int)
. При вызове метода getItem(int)
для позиции в массиве преступлений следует вернуть объект
CrimeFragment
, настроенный для вывода информации объекта в заданной позиции.
В классе
CrimePagerActivity добавьте следующий код для назначения
PagerAdapter класса
ViewPager и реализации его методов getCount()
и getItem(int)
Листинг 11.4. Назначение PagerAdapter (CrimePagerActivity.java)
public class CrimePagerActivity extends FragmentActivity {
private ViewPager mViewPager;
private ArrayList mCrimes;
@Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mViewPager = new ViewPager(this);
mViewPager.setId(R.id.viewPager);
setContentView(mViewPager);
mCrimes = CrimeLab.get(this).getCrimes();
FragmentManager fm = getSupportFragmentManager();
mViewPager.setAdapter(new FragmentStatePagerAdapter(fm) {
@Override
public int getCount() {
return mCrimes.size();
}
@Override
public Fragment getItem(int pos) {
Crime crime = mCrimes.get(pos);
return CrimeFragment.newInstance(crime.getId());
}
});
}
}

216
Глава 11. ViewPager
Пройдемся по этому коду. В первой строке мы получаем от
CrimeLab набор дан- ных — контейнер
ArrayList объектов
Crime
. Затем мы получаем экземпляр
Frag- mentManager для активности.
На следующем шаге адаптером назначается безымянный экземпляр
Fragment-
StatePagerAdapter
. Для создания
FragmentStatePagerAdapter необходим объект
FragmentManager
. Не забывайте, что
FragmentStatePagerAdapter
— ваш агент, управляющий взаимодействием с
ViewPager
. Чтобы ваш агент мог выполнить свою работу с фрагментами, возвращаемыми в getItem(int)
, он должен быть способен добавить их в активность. Вот почему ему необходим экземпляр
Frag- mentManager
(Что именно делает агент? Вкратце он добавляет возвращаемые фрагменты в ак- тивность и помогает
ViewPager идентифицировать представления фрагментов для их правильного размещения. Более подробная информация приведена в разделе
«Для любознательных» в конце главы).
Два метода
PagerAdapter весьма просты. Метод getCount()
возвращает текущее ко- личество элементов в списке. Все существенное происходит в методе getItem(int)
Он получает экземпляр
Crime для заданной позиции в наборе данных, после чего использует его идентификатор для создания и возвращения правильно настроен- ного экземпляра
CrimeFragment
Интеграция CrimePagerActivity
Теперь можно переходить к устранению класса
CrimeActivity и замене его классом
CrimePagerActivity
Для начала щелчок на элементе списка в
CrimeListFragment должен запускать экземпляр
CrimePagerActivity вместо
CrimeActivity
Вернитесь к файлу
CrimeListFragment.java и измените метод onListItemClick(…)
так, чтобы он запускал
CrimePagerActivity
Листинг 11.5. Запуск активности (CrimeListFragment.java)
@Override public void onListItemClick(ListView l, View v, int position, long id) {
// Получение объекта Crime от адаптера
Crime c = ((CrimeAdapter)getListAdapter()).getItem(position);
// Запуск CrimeActivity
Intent i = new Intent(getActivity(), CrimeActivity.class);
// Запуск CrimePagerActivity с объектом Сrime
Intent i = new Intent(getActivity(), CrimePagerActivity.class);
i.putExtra(CrimeFragment.EXTRA_CRIME_ID, c.getId());
startActivity(i);
}
Также необходимо добавить
CrimePagerActivity в манифест, чтобы ОС могла за- пустить эту активность. Пока манифест будет открыт, заодно удалите объявление
CrimeActivity

Интеграция CrimePagerActivity
217
Листинг 11.6. Добавление CrimePagerActivity в манифест (AndroidManifest.xml)




android:name=".CrimeActivity"
android:label="@string/app_name" >


android:label="@string/app_name">



Наконец, чтобы не загромождать проект, удалите
CrimeActivity.java на панели
Package
Explorer
Запустите приложение CriminalIntent. Нажмите на строке
Crime
#0
, чтобы про- смотреть подробную информацию. Проведите по экрану влево или вправо, чтобы просмотреть другие элементы списка. Обратите внимание: переключение страниц происходит плавно и без задержек. По умолчанию
ViewPager загружает элемент, находящийся на экране, а также по одному соседнему элементу в каждом направле- нии, чтобы отклик на жест прокрутки был немедленным. Количество загружаемых соседних страниц можно настроить вызовом setOffscreenPageLimit(int)
Однако с
ViewPager еще не все идеально. Вернитесь к списку при помощи кнопки
Back и нажмите на другом элементе. Вы снова увидите информацию первого эле- мента — вместо того, который был запрошен.
По умолчанию
ViewPager отображает в своем экземпляре
PagerAdapter первый элемент. Чтобы вместо него отображался элемент, выбранный пользователем, на- значьте текущим элементом
ViewPager элемент с указанным индексом.
В конце
CrimePagerActivity.onCreate(…)
найдите индекс отображаемого преступле- ния; для этого переберите и проверьте идентификаторы всех преступлений. Когда вы найдете экземпляр
Crime
, у которого поле mId совпадает с crimeId в дополнении интента, измените текущий элемент по индексу найденного объекта
Crime
Листинг 11.7. Назначение исходного элемента (CrimePagerActivity.java)
public class CrimePagerActivity extends FragmentActivity {
@Override public void onCreate(Bundle savedInstanceState) {
FragmentManager fm = getSupportFragmentManager();
mViewPager.setAdapter(new FragmentStatePagerAdapter(fm) {
});
продолжение


218
Глава 11. ViewPager
Листинг 11.7 (продолжение)
UUID crimeId = (UUID)getIntent()
.getSerializableExtra(CrimeFragment.EXTRA_CRIME_ID);
for (int i = 0; i < mCrimes.size(); i++) {
if (mCrimes.get(i).getId().equals(crimeId)) {
mViewPager.setCurrentItem(i);
break;
}
}
}
}
Запустите приложение CriminalIntent. При выборе любого элемента списка должна отображаться подробная информация правильного объекта
Crime
Также в приложение можно добавить еще одну функцию: заменить заголовок активности, выводимый на панели действий (строки заголовка на старых устрой- ствах), кратким описанием текущего объекта
Crime
. Для этого следует реализовать интерфейс
ViewPager.OnPageChangeListener
Листинг 11.8. Добавление OnPageListener (CrimePagerActivity.java)
@Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mViewPager = new ViewPager(this);
mViewPager.setId(R.id.viewPager);
setContentView(mViewPager);
mCrimes = CrimeLab.get(this).getCrimes();
FragmentManager fm = getSupportFragmentManager();
mViewPager.setAdapter(new FragmentStatePagerAdapter(fm) {
});
mViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
public void onPageScrollStateChanged(int state) { }
public void onPageScrolled(int pos, float posOffset, int posOffsetPixels) {
}
public void onPageSelected(int pos) {
Crime crime = mCrimes.get(pos);
if (crime.getTitle() != null) {
setTitle(crime.getTitle());
}
}
});
}
Метод onPageChangeListener используется для обнаружения изменений в странице, которая в настоящий момент отображается экземпляром
ViewPager
. При изменении страницы заголовку
CrimePagerActivity задается краткое описание
Crime
Нас интересует лишь то, какая страница является текущей, поэтому мы реализуем метод onPageSelected(…)
. Метод onPageScrolled(…)
сообщает, где будет находиться

Интеграция CrimePagerActivity
219
страница, а метод onPageScrollStateChanged(…)
— находится ли анимация стра- ницы в процессе активного перетаскивания, перехода в устойчивое состояние или в простое.
Запустите приложение CriminalIntent и убедитесь в том, что при каждом жесте прокрутки заголовок активности заполняется значением поля mTitle текущего объекта
Crime
. Вот и все! Теперь наш экземпляр
ViewPager полностью готов к работе.
FragmentStatePagerAdapter и FragmentPagerAdapter
Существует еще один тип
PagerAdapter
, который можно использовать в приложе- ниях; он называется
FragmentPagerAdapter
FragmentPagerAdapter используется точно так же, как
FragmentStatePagerAdapter
, и отличается от него только способом выгрузки неиспользуемых фрагментов.
Fragment
для Item1
текущий фрагмент
Переход на страницу вправо
Представ- ление
Представ- ление
Представ- ление
Представ- ление
Текущий фрагмент
Fragment
для Item2
Fragment
для Item3
Fragment
для Item1
Fragment
для Item2
Fragment
для Item3
Представ- ление
Рис. 11.3. Управление фрагментами FragmentStatePagerAdapter
При использовании класса
FragmentStatePagerAdapter неиспользуемый фрагмент уничтожается. Происходит закрепление транзакции для полного удаления фраг- мента из объекта
FragmentManager активности. Наличие «состояния» у
Fragment-
StatePagerAdapter определяется тем фактом, что экземпляр при уничтожении сохраняет объект
Bundle вашего фрагмента в методе onSaveInstanceState(Bundle)
Когда пользователь возвращается обратно, новый фрагмент восстанавливается по состоянию этого экземпляра.
С другой стороны,
FragmentPagerAdapter ничего подобного не делает. Когда фрагмент становится ненужным,
FragmentPagerAdapter вызывает для транзакции detach(Fragment)
вместо remove(Fragment)
. Представление фрагмента при этом

220
1   ...   16   17   18   19   20   21   22   23   ...   55

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

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

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