Главная » Разработка для Android » РЕАЛИЗАЦИЯ ЛОГИКИ ПРИЛОЖЕНИЯ

0

Вопросы, рассматриваемые в этом часе:

•            разработка дизайна игрового экрана; работа с элементами ViewSwitcher;

•            структуры данных и разбор XML-данных;

•            реализация логики игры и хранение состояния игры.

В этом часе вы реализуете главный экран приложения «Been There, Done Thai!» — игро­вой экран. Этот экран предлагает пользователю ответить на ряд вопросов опроса-викто­рины и сохраняет информацию о набранных им очках. Поскольку на этом экране должна отображаться динамическая последовательность изображений и текстовых строк, вы мо­жете воспользоваться несколькими новыми элементами-представлениями View, включая элементы imageSwitcher и TextSwitcher, которые помогут реализовать пере­ходы между вопросами викторины. Кроме того, вы также сможете реализовать в классе QuizGameActivity логику игры и добавить информацию о промежуточном состоя­нии игрового процесса, включая получение наборов новых вопросов по мере прохождения игры пользователем.

РАЗРАБОТКА ДИЗАЙНА ИГРОВОГО ЭКРАНА

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

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

Рис. 12.3. Измененный дизайн-макет игрового экрана приложения «Been There, Done That!» с элементами ImageSwitcher и TextSwitcher

РЕАЛИЗАЦИЯ МАКЕТА ИГРОВОГО ЭКРАНА

Реализацию игрового экрана вы начнете с добавления новых ресурсов в проект. Затем вы обновите файл макета game.xml, чтобы отразить подготовленный дизайн-макет игрового экрана.

Добавление новых ресурсов в проект

Для реализации игрового экрана вам потребуется несколько новых ресурсов:

•                строковые ресурсы (типа string) для текста, который будет отображаться на элементах Button, а также для текста, который будет отображаться в случае отсут­ствия доступных вопросов;

•               разнообразные ресурсы размеров (типа Dimension) и цветов (типа Color), необходимые для реализации дизайна элементов игрового экрана;

•               два ресурса с XML-данными, которые будут содержать наборы тестовых вопросов.

Вы уже без особого труда должны уметь создавать любые ресурсы типа String, Dimension и Color, необходимые для макета экрана, поэтому давайте поговорим о наборах тестовых вопросов.

Со временем вопросы, используемые в приложении «Been There, Done That!», будут загружаться с сервера в Интернете. Тем не менее пока вы создадите два набора тестовых вопросов, которые будут храниться локально в виде XML-файлов: /res/xml/samplequestions.xml и /res/xml/smaplequestions2.xml. В дальнейшем, когда вы реализуете сетевую поддержку в вашем приложении, эти XML-данные будут загружаться с удаленного сервера. Используя наборы тестовых вопросов, вы можете прямо сейчас заняться реализацией логики игры, не беспокоясь о функциональности, связанной с сете­вым взаимодействием.

Но зависимо от источника получения списки вопросов – локальная файловая система или удаленный сервер – XML-данные будут выглядеть одинаково. Вот пример этих данных:

<?xml version="1.0" encoding="utf-8"?> <!— This is a mock question XML chunk —> <questions>

<question

number="1" text=

"Have you ever been on an African safari?"

imageUrl=

"http://www.perlcfurl.org/Android/BeenThereDoneThat/Question s/q1.png"

/>

<question

number= "2" text=

"Have you ever climbed a mountain?"

imageUrl=

"http://www.perlgurl.org/Android/BeenThereDoneThat/Question s/q2.png"

/>

<question

number="3" text=

"Have you ever milked a cow?"

imageUrl=

"http://www.perlgurl.org/Android/BeenThereDoneThat/Question s/q3.png"

/>

</questions>

Как можно заметить, структура XML-данных очень проста. В ней присутствует один тег с именем < qu estions>, который может содержать несколько тегов < qu estion >. Каж­дый тег <question> имеет три атрибута: идентификатор вопроса (number), текст вопроса (text) и адрес URL изображения, связанного с данными (imageUrl). Обратите внимание, что вы используете изображения с удаленных источников в Интернете вместо того, чтобы добавлять все изображения для опросов в качестве ресурсов приложения.

Обновление макета игрового экрана

Файл макет game.xml определяет пользовательский интерфейс игрового экрана. Как и раньше, откройте редактор ресурсов среды разработки Eclipse и удалите все существующие элементы из макета. Далее выполните следующие шаги, чтобы соз­дать желаемый макет на базе ранее подготовленного дизайн-макета экрана.

1.                                 Добавьте новый элемент-контейнер LinearLayout и присвойте его атрибуту background значение @drawable/bkgrnd. Все остальные элементы будут добавляться внутрь этого элемета-котейнера LinearLayout;

2.                                 Добавьте элемент-контейнер RelativeLayout и присвойте сто атрибутам layout_width и layout_height значение wrap_cont ent.

3.                                 Добавьте четыре элемента ImageView внутрь элемента-контейнера RelativeLayout — но одному элементу для каждого угла экрана. Присвойте атрибуту src каждого элемента ImageView значение @drawable/quizicon. Присвойте атрибуту id каждого элемента ImageView уникальные            значения      @ + id/ImageView_Header, @+id/ImageView_Header2, @+id/ImageView_Header3 и @+ id/ImageView_Header4.

4.                                 Найдите элемент ImageView с атрибутом id, установленным в значение

ImageView_Header, и присвойте его атрибутам layout_alignParentLett и layout_alignParentTop значение true.

5.                                 Найдите элемент ImageView с атрибутом id, установленным в значение

ImageView_Header2, и присвойте его атрибутам layout_ alignParentRight иlayout_alignParentTop значение true.

6.                                 Найдите элемент ImageView с атрибутом id, установленным в значение

ImageView_Header3, и присвойте его атрибутам layout_alignParentLeft иlayout_alignParentBottom значение true.

7.                                 Найдите элемент ImageView с атрибутом id, установленным в значение ImageView_Header4,        и          присвойте                    его                                     атрибутам

layout_alignParentRight и layout_alignParentBottom значение true.

8.                Добавьте еще один элемент-контейнер RelativeLayout внутрь суще­

ствующего элемента-контейнера RelativeLayout, расположив его под элементом ImageView, чтобы создать область для вопросов викторины. Присвойте его атри­буту id значение @ + id/RelativeLayout_Content. Присвойте атрибутам layout_width и layout_height значение wrap_content. Кроме того, также присвойте его атрибуту gravity значение center, а атрибуту

layout_margin — значение 4 5рх.

9.                                 Внутрь только что добавленного элемента-контейнера RelativeLayout добавьте элемент ImageSwitcher с атрибутом id, установленным в значение

@ + id/ImageSwitcher_QuestionImage. Присвойте его атрибутам layout_width и layout_height значение wrap_content. Также присвойте его атрибутам layout_alignParentTop и layout_centerInParent значение true.

10.                              Добавьте момент TextSwitcher с атрибутом id, установленным в значение @ + id/TextSwitcher_QuestionText, под элементом ImageSwitcher. Присвойте его атрибутам layout_width и layout_height значение wrap_content. Также присвоите его атрибуту

layout_centerInParent значение true, а атрибуту layout_below — значение @ + id/ ImageSwitcher_QuestionImage.

11.                              Добавьте элемент Button с атрибутом id, установленным в значение @+id/Button_Yes, расположив его под элементом TextSwitcher. Присвойте его атрибутам layout_width и layout_height значение wrap_content. Также присвойте его атрибутам layout_alignParentBottom и layout_alignParentLeft значение true. Присвойте атрибуту text этого элемента строковый ресурс (значение Yes) и настройте его другие атрибуты так, чтобы элемент Button стал выглядеть привлекательно.

12.                              Добавьте еще один элемент Button с атрибутом id, установленным в значение @ + id/Button_No, расположив его под предыдущим элементом Button. Присвойте его атрибутам layout_width и layout_height значение wrap_content. Также присвойте его атрибутам layout_ alignParentBottom и layout_alignParentRight значение true. Присвойте атрибуту text этого элемента строковый ресурс (значение No) и настройте его другие атрибуты так, чтобы элемент Button стал выглядеть привлекательно.

Сохраните файл макета game.xml.

ВНИМАНИЕ! ______________________________________________________________

Редактор ресурсов среды разработки Eclipse не отображает элементы TextSwitcher и ImageSwitcher в режиме дизайна. Просмотр результирующих элементов TextView и ImageView, генерируемых указанными элементами, дол­жен осуществляться на эмуляторе Android. В данном случае редактор ресурсов не отражает реальный внешний вид приложения.

РАБОТА С ЭЛЕМЕНТАМИ VIEWSWITCHER

Для тех ситуаций, когда планируется, что деятельность будет постоянно обновлять со­держимое элемента View, инструментарий Android SDK предоставляет специальный ме­ханизм, реализуемый элементом ViewSwitcher. Элемент ViewSwitcher — это эффективный способ для обновления содержимого экрана. Элемент ViewSwitcher имеет два дочерних элемента-представления и позволяет управлять переходом между текущим дочерним элементом-представлением и дочерним элементом-представлением, который должен отображаться следующим. Дочерние элементы-представления View элемента ViewSwitcher могут генерироваться программным путем при помощи класса ViewFactory.

У класса ViewSwitcher есть два производных класса;

•             Класс TextSwitcher. Представляет элемент ViewSwitcher, который позволяет переключаться между двумя элементами TextView.

•             Класс ImageSwitcher. Представляет элемент ViewSwitcher, который позволяет переключаться между двумя элементами ImageView.

И хотя в любой произвольный момент времени элемент ViewSwitcher может иметь только два дочерних элемента-представления, последовательно он может отображать любое количество элементов-представлений View. Класс ViewFactory генерирует содержимое следующего элемента-представления, так что элементы ImageSwitcher и TextSwitcher могут последовательно отображать изображения и тексты вопросов.

ЗНАЕТЕ ЛИ ВЫ, ЧТО… _____________________________________________________

Вы можете создать пользовательский элемент ViewSwitcher. реализовав ваш собственный класс, производный от класса ViewSwitcher.Использование класса ViewFactory для генерации элементов-представлений View элемента ViewSwitcher.

Использование класса ViewFactory для генерации элементов-представлений View элемента ViewSwitcher

При создании экземпляра элемента ViewSwitcher вы можете указать подходящий класс ViewFactory, используя метод setFactory(). Класс ViewFactory имеет всего один обязательный метод — метод makeView(). Этот метод должен возвращать элемент- представление View подходящего типа. Например, класс ViewFactory для элемента TextSwitcher должен возвращать правильно настроенный элемент-представление TextView, а класс ViewFactory для элемента ImageSwitcher — правильно настроенный элемент-представление ImageView.

Ниже представлена реализация класса ViewFactory для элемента ImageSwitcher, которая может быть использована для генерации изображений к каждому вопросу на игровом экране: private class MylmageSwitcherFactory implements

ViewSwitcher.ViewFactory {

public View makeView() {

ImageView imageView = new ImageView(QuizGameActivity.this); imageView.setScaleType(ImageView.ScaleType.FIT_CENTER); imageView .setLayoutParams(new ImageSwitcher.LayoutParams(

LayoutParams. FILL_PARENT, LayoutParams. FILL_PARENT)); return imageView ;

}

}

Обратите внимание, что источник, или содержимое, элемент-представления не устанавливается в методе makeView(). Вместо этого, вы можете рассматривать возвращаемый элемент-представления как шаблон для элемента ViewSwitcher, который будет применяться для отображения каждого дочернего элемента-представления.

Создавая экземпляр элемента ViewSwitcher, вы можете указать используемый им класс VlewFactory при помощи метода setFactory () . Например, чтобы указать в качестве класса ViewFactory для элемента ImageSwitcher созданный вами класс MyImageSwitcherFactory, вы можете сделать следующее:

ImageSwitcher questionImageSwitcher =

(ImageSwitcher) findViewById(R.id.ImageSwitcher_QuestionImage); questionImageSwitcher.setFactory(new MyImageSwitcherFactory());

Подобным образом вы должны создать производный класс от класса ViewFactory, который будет генерировать элементы-представления TextView для каждого вопроса на игровом экране. Ниже представлена реализация класса MyTextSwitcherFactory, производного от класса ViewFactory, который делает именно то, что нужно:

private class MyTextSwitcherFactory implements

ViewSwitcher.ViewFactory { public View makeView() {

TextView textView = new TextView(QuizGameActivity.this); textView.setGravity(Gravity. CENTER); Resources res = getResources();

float dimension = res.getDimension(R.dimen. game_question_size);

int titleColor = res.getColor(R.color.title_color);

int shadowColor = res.getColor(R.color.title_glow);

textView.setTextSize(dimension);

textView.setTextColor(titleColor);

textView.setShadowLayer(10, 5, 5, shadowColor);

return textView;

}

}

Обратите внимание, что, как и в случае с реализацией класса MyImageSwitcherFactory, в классе MyTextSwitcherFactory также реализуется метод makeView() – на этот раз данный метод генерирует подходящий элемент- представление TextView с заданными значениями атрибутов размера текста, цвета и притяжения.

Работа с элементом TextSwitcher

Элемент TextSwitcher позволяет деятельности анимировать переход между двумя элементами-представлениями TextView. Вам нужно добавить элемент TextSwitcher с именем TextSwitcher QuestiorTAx* на макет игрового экрана для отображения вопросов викторины пользователю.

ИНИЦИАЛИЗАЦИЯ ЭЛЕМЕНТА TEXTSWITCHER

Для инициализации элемента TextSwitcher вы просто указываете подходящую реализацию класса ViewFactory и затем используете метод setCurrentText () , как показано в следующем коде:

TextSwitcher questionTextSwitcher = (TextSwitcher) findViewById(R.id.TextSwitcher_QuestionText);

questionTextSwitcher.setFactory(new MyTextSwitcherFactory()); questionTextSwitcher.setCurrentText("First Text String");

ОБНОВЛЕНИЕ СОДЕРЖИМОГО ЭЛЕМЕНТА TEXTSWITCHER

Когда вы хотите обновить содержимое элемента TextSwitcher, добавив новый элемент-представление TextView, вы можете вызвать метод setText () :

TextSwitcher questionTextSwitcher = (TextSwitcher) findViewById(R.id.TextSwitcher_QuestionText);

questionTextSwitcher.setText("Next Text String");

Вызов         метода      setText ()            заставляет              экземпляр              класса

MyTextSwitcherFactory сгенерировать новый элемент-представление TextView и заполнить его содержимым типа String, переданным в качестве па­раметра метода setText () .

Работа с элементом ImageSwitcher

Элемент ImageSwitcher позволяет деятельности анимировать переход между двумя элементами-представлениями ImageView. Вы добавили элемент ImageSwitcher с именем ImageSwitcher_QuestionText на макет игрового экрана для отображения изображения, связанного с каждым вопросом викторины, пользователю.

ИНИЦИАЛИЗАЦИЯ ЭЛЕМЕНТА IMAGESWITCHER

Для инициализации элемента ImageSwitcher вы просто указываете подходящую реализацию класса ViewFactory и затем используете один из трех методов, чтобы установить изображение. В следующем коду продемонстрировано использование метода

setImageDrawable() :

КСТАТИ _________________________________________________________________

К сожалению, в настоящее время использовать метод setlmageURL () элемента ImageSwitcher для указания адресов URL ресурсов, размещенных в Интернете, невозможно. Вместо этого вам нужно проделать дополнительную работу, свя­занную с загрузкой изображения по указанному адресу URL и сохранением этого изображения в виде объекта типа Drawable. Представленная ниже реализация метода getQuestionImageDrawable () делает именно то, что нужно:

private Drawable getQuestionImageDrawable(int questionNumber) { Drawable image; URL imageUrl;

try {

// Create a Drawable by decoding a stream from a remote URL imageUrl = new URL(getQuestionImageUrl(questionNumber)); Bitmap bitmap = BitmapFactory. decodeStzeam(imageUrl.openStream()); image = new BitmapDrawable(bitmap); } catch (Exception e) {

Log.e(DEBUG_TAG, "Decoding Bitmap stream failed.");

image = getResources().getDrawable(R.drawable.noquestion); }

return image; }

Метод getQuestionImageUrl ( ) — это простой вспомогательный метод, ко­торый получает подходящий веб-адрес изображения для указанного вопроса. Эта информация хранится в объекте типа Hashtable с вопросами. (Мы поговорим о том, как обрабатываются вопросы, далее.) Полная реализация метода getQuestionlmageUrl () доступна в исходном коде на диске, прилагаемом к данной книге.

Класс URL используется для хранения удаленного адреса файла изображения в формате PNG, которое вы хотите загрузить в элемент ImageSwitcher. После этого вы выгружаете полученные данные в объект типа BitmapDrawable. На­конец, чтобы использовать методы для работы с потоком, приложению требуется разрешение android.permission.INTERNET, которое должно быть добавлено в файл манифеста Android.

ОБНОВЛЕНИЕ СОДЕРЖИМОГО ЭЛЕМЕНТА IMAGESWITCHER

Когда вы хотите обновить содержимое элемента ImageSwitcher, добавив новый элемент-представление ImageView, вы можете вызвать метод setImageDrawable () :

ImageSwitcher questionImageSwitcher =

(ImageSwitcher) findViewById(R.id.ImageSwitcher_QuestionImage); Drawable image = getQuestionImageDrawable(nextQuestionNumber); questionImageSwitcher.setImageDrawable(image);

Вызов метода setlmageDrawable () заставляет экземпляр класса MyImageSwitcher Factory сгенерировать новый элемент-представление irageView с объектом типа Drawable, переданным в качестве параметра метола

setImageDrawable ().

Использование анимации для элемента ViewSwitcher

Чтобы анимировать переход между дочерними элементами-представлениями View эле­мента ViewSwitcher, применяются методы setInAnimation () и setOutAnimation() . Например, чтобы добавить анимацию плавного появления и плавного исчезновения элементов-предстаатений в элементе TextSwitcher, вы могли бы загрузить и использовать встроенные анимации платформы Android, как показано в следующем коде:

Animation in = AnimationUtils.loadAnimation(this, android.R.anim.fade_in);

Animation out = AnimationUtils.loadAnimation(this, android.R.anim.fade_out); TextSwitcher questionTextSwitcher =

(TextSwitcher) findViewById(R.id.TextSwitcher_QuestionText); questionTextSwitcher.setInAnimation(in); questionTextSwitcher.setOutAnimation(out);

Теперь при каждом вызове метода setText () или метода setCurrentText () эле­мента TextSwitcher будет запускаться анимация, имитирующая плавное появление или исчезновение текста. Вы можете еще больше улучшить процесс перехода между вопросами, добавив предыдущие анимации к элементу ImageSwitcher, который используется для отображения изображений, связанных с вопросами.

РЕАЛИЗАЦИЯ ЛОГИКИ ИГРЫ

Приложение «Been There, Done That!» основано на расширяемом списке вопросов викто­рины. И именно поэтому вы не можете хранить все вопросы в виде ресурсов, а должны придумать простой способ получения новых вопросов на лету. Кроме того, храня весь список вопросов викторины на удаленном сервере, вы оптимизируете приложение, функционирующее на мобильном телефоне, путем экономии дискового пространства.

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

1.                                  Добавьте параметры, представляющие текущее состояние игры, в экземпляр класса SharedPreferences.

2.                                  Реализуйте получение и разбор наборов вопросов викторины (в формате XML) в подходящую структуру данных.

3.                                  Реализуйте обработку событий нажатий по элементу Button, чтобы об­новлять содержимое элементов ImageSwitcher и TextSwitcher, а также управлять логикой игры.

4.                                  Обработайте крайние случаи, например, ситуацию, когда больше нет доступных вопросов.

5.                                  В следующих разделах эти шаги описываются более подробно.

ДОБАВЛЕНИЕ ПАРАМЕТРОВ, ХРАНЯЩИХ ТЕКУЩЕЕ СОСТОЯНИЕ ИГРЫ, В ЭКЗЕМПЛЯР КЛАССА SHAREDPREFERENCES

Чтобы отслеживать текущее состояние игры, вы должны добавить два дополнительных параметра типа Integer в экземпляр класса SharedPreferences приложения: промежуточный результат игры и текущий номер вопроса. Для добавления этих параметров вы сначала должны объявить строковые значения с названиями параметров в классе QuizActivity:

public static final String GAME_PREFERENCES_SCORE = "Score";

public static final String GAME_PREFERENCES_CURRENT_QUESTION =

"CurQuestion";

Затем вы объявляете объект типа SharedPreferences в качестве переменной-члена класса QuizGameActivity:

SharedPreferences mGameSettings;

Переменная-член mGameSettings инициализируется в методе onCreate() класса QuizGameActivity:

mGameSettings = getSharedPreferences(GAME_PREFERENCES, Context. MODE_PRIVATE);

Теперь, no мере необходимости, и любом месте класса ни можете /’.пользовать объект типа SharedPreferences для чтения и сохранения состояния игры, а именно номера текущего вопроса и промежуточною результата игры. Например, вы можете получить номер текущего («опроса, используя метод getInt () класса Share dPreference s , как показано ниже:

int startingQuestionNumber =

mGameSettings.getInt( GAME_PREFERENCES_CURRENT_QUESTION, 0);

ПОЛУЧЕНИЕ, РАЗБОР И ХРАНЕНИЕ ДАННЫХ С ВОПРОСАМИ ВИКТОРИНЫ

Когда у приложения «Been There, Done That!» заканчиваются вопросы для отображения, оно пытается получить новый набор вопросов. Выбранная нами архитектура упрощает реализацию сетевой поддержки в приложении, рассматриваемую в следующих часах, поскольку процедура разбора XML- данных останется прежней.

Каждый набор вопросов представлен простым XML-файлом, содержимое которого должно быть разобрано. Вы можете сохранить текущий набор вопросов в памяти, используя простую, но очень мощную структуру данных — в данном случае, это переменная-член типа Hashtable.

ОБЪЯВЛЕНИЕ ПОЛЕЗНЫХ СТРОКОВЫХ ЛИТЕРАЛОВ ДЛЯ РАЗБОРА ВОПРОСОВ

Уделите немного времени, чтобы изучить формат XML-данных, используемый для хранения наборов вопросов, который был рассмотрен ранее. Чтобы разобрать наборы вопросов, вам потребуется добавить несколько строковых литералов, представляющих XML-теги и атрибуты, в класс QuizActivity:

public static final String XML_TAG_QUESTION_BLOCK = "questions"; public static final String XML_TAG_QUESTION = "question"; public static final String XML_TAG_QUESTION_ATTRIBUTE_NUMBER =

"number";

public static final String XML_TAG_QUESTION_ATTRIBUTE_TEXT = "text"; public static final String XML_TAG_QUESTION_ATTRIBUTE_IMAGEURL =

"imageUrl";

И, раз уж вы работаете с этим файлом, можете также определить размер набора вопросов по умолчанию, чтобы упростить процесс выделения памяти для хранения вопросов в процессе разбора XML-данных:

public static final int QUESTION_BATCH_SIZE = 15;

СОХРАНЕНИЕ ТЕКУЩЕГО НАБОРА ВОПРОСОВ В ОБЪЕКТЕ ТИПА HASHTABLE

Теперь внутри класса QuizGameActivity вы можете реализовать простой вспомогательный класс с именем Question, который будет использоваться им представления каждого вопроса викторины:

private class Question { int mNumber; String mText; String mImageUrl;

public Question(int questionNum, String questionText, String questionImageUrl) { mNumber = questionNum; mText = questionText; mImageUrl = questionImageUrl;

}

}

Вы не будете хранить все вопросы локально. Вместо этого вы будете подгружать наборы вопросов по мере необходимости (пока из локальных тестовых XML-файлов, в дальнейшем — из Интернета). Вам необходимо место для хранения этих вопросов, поэтому объявите переменную-член типа Hashtable внутри класса QuizGameActivity, которая будет хранить набор объектов типа Question в памяти после завершения разбора XML-данных:

Hashtable<Integer, Question> mQuestions;

ЗНАЕТЕ ЛИ ВЫ, ЧТО… ____________________________________________________

Инструментарий Android SDK включает множество классов, широко используемых при разработке приложений на платформе Java. Например, в пакете java.util вы найдете многие знакомые вам структуры данных (например, класс Hashtable) и вспомогательные классы, а в пакете android.util доступны дополнительные специа­лизированные классы.

Вы можете создать экземпляр класса Hashtable и присвоить его соответствующей переменной-члену в методе onCreate () класса QuizGameActivity, как показано в следующем коде:

mQuestions = new Hashtable<Integer, Question>(QUESTION_BATCH_SIZE);

Теперь, предположив, что у нас есть некие XML-данные, представляющие новый набор вопросов, мы можем создать объект типа XmlResourceParser с именем question- Batch. Объект типа XmlResourceParser может быть использован для извлечения данных для каждого вопроса и сохранения этих данных в виде экземпляра класса Question в переменной-члене типа Hashtable при помощи put (), как показано ниже:

String questionNumber =

questionBatch.getAttributeValue(null, XML_TAG_QUESTION_ATTRIBUTE_NUMBER); Integer questionNum =

new Integer(questionNumber); String questionText =

questionBatch.getAttributeValue(null, XML_TAG_QUESTION_ATTRIBUTE_TEXT); String questionImageUrl =

questionBatch.getAttributeValue(null, XML_TAG_QUESTION_ATTRIBUTE_IMAGEURL);

// Save data to our hashtable mQuestions.put(questionNum,

new Question(questionNum, questionText, questionImageUrl));

Вы можете проверить существование определенного вопроса в переменной- члене типа Hashtable по номеру этого вопроса при помощи метода containsKey () . Вы также можете получить определенный экземпляр класса Question по номеру вопроса, используя метод get () :

Question curQuestion = (Question) mQuestions.get(questionNumber);

ОБРАБОТКА СОБЫТИЙ НАЖАТИЙ НА КНОПКИ

Элементы Button на игровом экране используются для управления элементами ImageSwitcher и TextSwitcher. Каждый раз, когда пользователь нажимает любой из элементов Button, происходит сохранение промежуточного результата игры и обновление элементов ViewSwitcher для отображения следующего вопроса. Таким образом, элементы Button заставляют деятельность «продвигаться» вперед, перемещая пользователя по вопросам викторины.

Существует небольшое отличие между обработкой событий нажатий на кнопки Yes (Да) и No (Нет). Давайте рассмотрим метод OnClickListener.OnClick() для элемента Button, представляющего кнопку Yes (Да):

Button yesButton = (Button) findViewById(R.id.Button_Yes); yesButton.setOnClickListener(new View.OnClickListener() { public void onClick(View v) {

handleAnswerAndShowNextQuestion(true);

}

});

Метод View.onClick.Listener() для элемента Button, представляющего кнопку No (Нет), практически идентичен обработчику событий нажатий на кнопки Yes (Да), показанному выше. Единственное отличие заключается в том, что в метод handleAnswerAndShowNextQuestion () передается значение false. Это пользова­тельский метод, который вы реализуете для обработки промежуточных результатов игры и управления любой логикой, связанной с элементами ViewSwitcher.

Теперь           давайте                более               подробно               рассмотрим               метод

handleAnswerAndShowNextQuestion(), принимающий один параметр — boolean bAnswer. Сна- чата взгляните на следующий псевдокод, демонстрирующий то, что происходит в этом обработчике событий нажатий на элемент Button:

private void handleAnswerAndShowNextQuestion(boolean bAnswer) { // Загрузить состояние игры, включая промежуточный результат // Обновить промежуточный результат игры, если пользователь нажал кнопку "yes"

// Загрузить следующий вопрос, обработав ситуацию, когда вопросов не

осталось }

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

SharedPreferences:

int curScore =

mGameSettings.getInt(GAME_PREFERENCES_SCORE, 0);

int nextQuestionNumber =

mGameSettings.getInt( GAME_PREFERENCES_CURRENT_QUESTION, 1) + 1;

После этого вам нужно увеличить значение номера следующего вопроса, хранящегося в экземпляре класса SharedPreferences:

Editor editor = mGameSettings.edit();

editor.putInt(GAME_PREFERENCES_CURRENT_QUESTION, nextQuestionNumber);

Если пользователь щелкнул по кнопке Yes (Да), вам также нужно обновить промежуточный результат игры и сохранить его в экземпляре класса

SharedPreferences:

if (bAnswer == true) {

editor.putInt(GAME_PREFERENCES_SCORE, curScore + 1);

}

После того, как вы изменили все необходимые значения в экземпляре класса SharedPreferences, вы сохраняете все изменения при помощи метода commit () класса Editor: editor.commit();

Далее вы проверяете, доступен ли в объекте типа Hashtable следующий вопрос. Если вам нужно получить новый набор вопросов, сделайте это сейчас:

if (mQuestions.containsKey(nextQuestionNumber) == false) { // Загружаем следующий набор вопросов try {

loadQuestionBatch(nextQuestionNumber); } catch (Exception e) {

Log.e(DEBUG_TAG, "Loading updated question batch failed", e);

}

}

Наконец, вы обновляете элементы TextSwitcher и ImageSwitcher, используя текст и изображение для следующего вопроса:

if (mQuestions.containsKey(nextQuestionNumber) == true) { // Обновляем текст вопроса TextSwitcher questionTextSwitcher =

(TextSwitcher) findViewById(R.id. TextSwitcher_QuestionText); questionTextSwitcher.setText(getQuestionText(nextQuestionNumber));

// Обновляем изображение связанное с вопросом ImageSwitcher questionImageSwitcher = (ImageSwitcher)

findViewById(R.id.ImageSwitcher_QuestionImage);

Drawable image = getQuestionImageDrawable(nextQuestionNumber); questionImageSwitcher.setImageDrawable(image); } else {

handleNoQuestions();

}

Рис. 12.4. Игровой экран приложения «Been There, Done That!» Когда вы запустите приложение и откроете игровой экран, он должен выглядеть наподобие экрана, изображенного на рис. 12.4.

ЗНАЕТЕ ЛИ ВЫ, ЧТО… ___________________________________________________

Существует два простых способа «сбросить» текущее состояние викторины для отладочных целей. Первый метод заключается в удалении файла, используемого экземпляром класса SharedPreferences приложения, из файловой системы Android и перезапуске эмулятора. При помощи перспективы DDMS среды разра­ботки Eclipse вы открываете каталог с данными приложениями и удаляете связан­ный с приложением файл, который используется экземпляром класса SharedPreferences. Также вы можете удалить и повторно установить приложе­ние, используя пункт меню Settings (Настройки) на домашнем экране операцион­ной системы Android. Добавление механизма сброса настроек приложения «Been There, Done That!» дается читателю в качестве упражнения в конце этого часа.

ОБРАБОТКА КРАЙНИХ СЛУЧАЕВ

Когда больше нет доступных вопросов, вы должны сообщить об этом пользователю. Этот случай обрабатывается методом handleNoQuestions() Сначала в качестве текста вопроса и связанного с ним изображения вы устанавливаете соответствующие значения, как показано в следующем коде:

TextSwitcher questionTextSwitcher =

(TextSwitcher) findViewById(R.id. TextSwitcher_QuestionText); questionTextSwitcher.setText(getResources().getText(R.string.no_questi ons));

ImageSwitcher questionImageSwitcher =

(ImageSwitcher) findViewById(R.id.ImageSwitcher_QuestionImage); questionImageSwitcher.setImageResource(R.drawable.noquestion); The Been There, Done That! game screen.

Также вы должны использовать эту возможность для отключения элементов:

Button yesButton =

(Button) findViewById(R.id.Button_Yes);

yesButton.setEnabled(false);

Button noButton =

(Button) findViewById(R.id.Button_No); noButton.setEnabled(false);

Рис. 12.5. Игровой экран приложения

«Been There, Done That!», когда больше нет доступных вопросов

Когда у приложения заканчиваются вопросы, игровой экран выглядит так, как показано на рис. 12.5. Пользователю сообщается о том, что доступных вопросов больше нет и он больше не может нажимать на элементы Button. Вместо этого он должен нажать кнопку Back на мобильном телефоне и вернуться в основное меню.

ИТОГИ

В этом часе вы реализовали наиболее важный экран приложения «Been There. Done That!» — игровой экран. Вы узнали, как можно анимировать переходы между элементами- представлениями view при помощи элементов ImageSwitcher и TextSwitcher. Также вы бегло познакомились с различными структурами данных, доступными в инструментарии Android SDK, и использовали переменную-член типа Hashtable для хранения набора вопросов, полученных в результате разбора XML-данных. Наконец, вы использовав экземпляр класса SharedPreferences для хранения настроек, представляющих текущее состояние игры.

ВОПРОСЫ И ОТВЕТЫ

Вопрос: Если я храню изображения локально, могу ли я использовать метод

setlmageURL () элемента ImageSwitcher вместо метода setImageDrawable () ?

Ответ: Безусловно. На самом деле, мы даже рекомендуем использовать именно этот подход. Если изображение хранится локально, использование метода setImageURL() существенно упрощает код, реализующий загрузку изображения в элемент ImageSwitcher (или ImageView). В данном случае нет необходимости создавать потоки или объекты типа Drawable в памяти.

Вопрос: Могу ли я при использовании элемента ViewSwitcher устанавливать свою собственную анимацию?

Ответ: Да, вы можете создать любую анимацию, которую хотите использовать для перехода между текущим элементом-представлением View и новым элементом- представлением View. Тем не менее необходимо помнить, что, как только произошел переход между элементами-представлениями View, единственный способ вернуться к прежнему элементу-представлению — это установить прежний элемент-представление в качестве следующего элемента-представления View. Для элемента ViewSwitcher не существует понятия «предыдущий элемент-представление View».

ПРАКТИКУМ Контрольные вопросы

1.                                Какие классы наследуются от класса ViewSwitcher?

A.                                TextSwitcher;

B.                                VideoSwitcher;

C.                                 ImageSwitcher;

D.                                AudioSwitcher.

2.                                 Верно ли это? Элементы TextView, используемые элементом TextSwitcher, должны быть определены до начала использования элемента

TextSwitcher.

3.                                  Верно ли это? Стандартные пакеты, например java.io, java.math, java.net и java.util, доступны в инструментарии Android SDK.

Ответы

1.                                 А и В. Класс ViewSwitcher имеет два производных класса; TextSwitcher (для анимации переходов между двумя элементами Textview) и ImageSwitcher (для анимации переходов между двумя элементами ImageView).

2.                                 Неверно. Элементы TextView, отображаемые при помощи элемента TextSwitcher, могут создаваться на лету с использованием экземпляра класса

ViewFactory.

3.                                 Верно. Многие стандартные пакеты платформы Java доступны в инструментарии Android SDK. Также существует ряд пакетов, разработанных специально для платформы Android, которые доступны в дереве пакетов android.*.

Полный список доступных пакетов можно найти в документации к инструментарию Android SDK.

Литература: Дэрси JI., Android за 24 часа. Программирование приложений под операционную систему Google/ ДэрсиЛ., КондерШ. — М.: Рид Групп, 2011. — 464 с. — (Профессиональные компьютерные книги). ISBN 978-5-4252-0318-2

По теме:

  • Комментарии