Глава 4. Отладка приложений Android Теперь выберите, какие исключения должны перехватываться. Введите имя Run- timeException и выберите любые из предлагаемых вариантов. RuntimeException является суперклассом NullPointerException , ClassCastException и других проблем времени выполнения, с которыми вы можете столкнуться, поэтому этот вариант удобен своей универсальностью. Впрочем, чтобы он перехватывал типы субклассов исключений, необходимо сделать еще кое-что. Переключитесь на перспективу Debug и взгляните на панель Breakpoints Вы увидите в ней новую точку прерывания для RuntimeException . Щелкните на ней и выберите команду Subclasses of this exception , чтобы отладчик прерывал работу и при получении NullPointerException Включите отладку GeoQuiz. На этот раз отладчик сразу переходит к строке, в ко- торой произошло исключение, — замечательно. Учтите, что если эта точка прерывания останется включенной во время отладки, она может сработать на инфраструктурном коде или в других местах, на которые вы не рассчитывали. Не забудьте отключить ее, если она не используется. File Explorer Перспектива DDMS предоставляет другие эффективные средства контроля за ра- ботой приложения, включая очень удобный файловый менеджер. Выберите панель File Explorer в группе вкладок справа. Рис. 4.11. Файловый менеджер В файловом менеджере можно просматривать файловую систему устройства, за- гружать и отправлять файлы. На физическом устройстве вы не сможете заглянуть в каталог /data , но в эмуляторе это возможно — следовательно, вы можете просма- тривать область хранения данных своего приложения. В новейшей версии Android эта область находится в каталоге /data/data/ [имя пакета]
Особенности отладки Android 101 Рис. 4.12. Каталог данных GeoQuiz (в эмуляторе) Пока здесь смотреть не на что, но в главе 17 файловый менеджер будет использо- ваться для просмотра файлов, записанных в закрытое хранилище. Особенности отладки Android Обычно процесс отладки в Android не отличается от обычной отладки кода Java. Тем не менее у вас могут возникнуть проблемы в областях, специфических для Android (например, ресурсы), о которых компилятор Java ничего не знает. Android Lint На помощь приходит Android Lint — статический анализатор кода Android. Статические анализаторы проверяют код на наличие дефектов, не выполняя его. Android Lint использует свое знание инфраструктуры Android для проверки кода и выявления проблем, которые компилятор обнаружить не может. Как правило, к рекомендациям Android Lint стоит прислушиваться. В главе 6 вы увидите, как Android Lint выдает предупреждение о проблеме совме- стимости. Кроме того, Android Line может выполнять проверку типов для объектов, определенных в XML. Попробуйте включить в QuizActivity следующую ошибку преобразования типов. Листинг 4.6. Ошибка в указании типа (QuizActivity.java) @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.d(TAG, "onCreate() called"); setContentView(R.layout.activity_quiz); mQuestionTextView = (TextView)findViewById(R.id.question_text_view); mTrueButton = (Button)findViewById(R.id.true_button); продолжение
102 Глава 4. Отладка приложений Android Листинг 4.6 (продолжение) mTrueButton = (Button)findViewById(R.id.question_text_view); } Из-за указания неверного идентификатора ресурса код попытается преобразовать TextView в Button во время выполнения, что приведен к исключению неправильного преобразования типа. Компилятор Java не видит проблем в этом коде, но Android Lint обнаружит ошибку еще до запуска приложения. На панели Package Explorer щелкните правой кнопкой мыши на проекте GeoQuiz и выберите команду Android Tools Run Lint: Check for Common Errors ; появляется панель Lint Warnings (рис. 4.13). Рис. 4.13. Предупреждения Lint В данном случае Android Lint выдает одну ошибку и одно предупреждение. Ошибка нам уже известна: с неверным идентификатором ресурса преобразование к типу Button завершится неудачей. Исправьте ошибку в onCreate(Bundle) Листинг 4.7. Исправление простой ошибки (QuizActivity.java) @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.d(TAG, "onCreate() called"); setContentView(R.layout.activity_quiz); mQuestionTextView = (TextView)findViewById(R.id.question_text_view); mTrueButton = (Button)findViewById(R.id.question_text_view); mTrueButton = (Button)findViewById(R.id.true_button); } Предупреждение от Android Lint не столь вразумительно. В нем рекомендуется использовать тег merge для layout-land/activity_quiz.xml . К сожалению, Android Lint здесь ошибается. Не заменяйте FrameLayout тегом merge , потому что FrameLayout используется для конкретного позиционирования ваших виджетов.
Особенности отладки Android 103 Проблемы с классом R Всем известны ошибки построения, которые возникают из-за ссылок на ресурсы до их добавления (или удаления ресурсов, на которые ссылаются другие файлы). Обычно повторное сохранение файла после добавления ресурса или удаления ссыл- ки приводит к тому, что Eclipse проводит построение заново, а проблемы исчезают. Однако иногда такие ошибки остаются или появляются ниоткуда. Если вы столк- нетесь с подобной ситуацией, попробуйте принять следующие меры. Запустите Android Lint Выполните команду Window Run Android Lint . Часто запуск Line налаживает нару- шенные связи между составляющими проекта. Выполните чистку проекта Выполните команду Project Clean . Eclipse строит проект заново, а результат по- строения нередко избавляется от ошибок. Проверьте разметку XML в файлах ресурсов Если файл R.java не был сгенерирован при последнем построении, то все ссылки на ресурс будут сопровождаться ошибками. Часто ошибки вызваны опечатками в разметке одного из файлов XML. Разметка макета не проверяется, поэтому среда не сможет привлечь ваше внимание к опечаткам в таких файлах. Если вы найдете ошибку и заново сохраните файл, код R.java будет сгенерирован заново. Удаление каталога gen Если вам не удается заставить Eclipse сгенерировать новый файл R.java , попробуйте удалить весь каталог gen . При повторном построении Eclipse создает новый каталог gen с работоспособным классом R Если у вас все еще остаются проблемы с ресурсами (или иные проблемы), отдо- хните и просмотрите сообщения об ошибках и файлы макета «на свежую голову». В запале легко пропустить ошибку. Также проверьте все ошибки и предупреждения Android Lint. При спокойном повторном рассмотрении сообщений нередко выяв- ляются ошибки или опечатки. Наконец, если вы зашли в тупик или у вас возникли другие проблемы с Eclipse, обратитесь к архивам https://stackoverflow.com или посетите форум книги по адресу https://forums.bignerdranch.com
Вторая активность В этой главе мы добавим в приложение GeoQuiz вторую активность. Как было сказано ранее, активность управляет информацией на экране; новая активность добавит в приложение второй экран, на котором пользователю будет предложено увидеть ответ на текущий вопрос. Рис. 5.1. CheatActivity позволяет подсмотреть ответ на вопрос Если пользователь решает просмотреть ответ, а затем возвращается к QuizActivity и отвечает на вопрос, он получает новое сообщение. 5
Создание второй активности 105 Рис. 5.2. QuizActivity знает, что вы жульничаете Почему эта задача является хорошим упражнением по программированию Android? Потому что вы научитесь: создавать новую активность и новый макет без помощи мастера новых при- ложений; запускать активность из другой активности (вы приказываете ОС создать эк- земпляр активности и вызвать его метод onCreate(Bundle) ); передавать данные между родительской (запускающей) и дочерней (запущен- ной) активностью. Создание второй активности В этой главе нам предстоит много сделать. Мы начнем с создания нового макета для CheatActivity , после чего создадим сам класс CheatActivity Но сначала откройте файл strings.xml и добавьте строки, необходимые для этой главы. Листинг 5.1. Добавление строк (strings.xml)
Lake Baikal is the world\'s oldest and deepest freshwater lake. Cheat! Are you sure you want to do this? Show Answer Cheating is wrong.
106 Глава 5. Вторая активность Создание нового макета На рис. 5.1 показано, как должно выглядеть представление CheatActivity Определения виджетов приведены на рис. 5.3. Рис. 5.3. Схема макета CheatActivity Чтобы создать файл макета, щелкните правой кнопкой мыши на каталоге res/layout на панели Package Explorer и выберите команду New Other... В папке Android найдите и выберите строку Android XML Layout File (рис. 5.4). Щелкните на кнопке Next Рис. 5.4. Создание нового файла макета
Создание второй активности 107 В открывшемся диалоговом окне введите имя файла макета activity_cheat.xml и вы- берите корневой элемент LinearLayout . Щелкните на кнопке Finish Рис. 5.5. Ввод имени и настройка параметров нового файла макета Когда файл откроется, перейдите к разметке XML. Обратите внимание: мастер включил в начало файла строку
Эта строка не является обязательной для файлов макетов XML, но она все равно добавляется в файлы, создаваемые некоторыми источниками (включая этого ма- стера создания макета). (Кстати говоря, если вы терпеть не можете графические интерфейсы, использовать мастера не обязательно. Просто создайте новый файл с именем fragment_crime.xml в ка- талоге res/layout и обновите папку res/layout , чтобы среда Eclipse нашла этот файл. Это относится к большинству мастеров Eclipse; ничто не мешает вам создавать файлы XML и файлы классов Java тем способом, который вы предпочитаете. Единственный мастер, без которого вам не обойтись, — это мастер новых приложений Android). Мастер создания макета сгенерировал корневой элемент LinearLayout за вас. Оста- ется лишь добавить атрибут android:gravity и трех потомков.
108 Глава 5. Вторая активность Попробуйте создать разметку XML для activity_cheat.xml по образцу рис. 5.3. После главы 8 в тексте вместо длинных фрагментов XML будут приводиться только схемы макетов вроде рис. 5.3, так что вам стоит освоить самостоятельное создание XML макетов. Сравните свою работу с листингом 5.2. Переключение ориентации Рис. 5.6. Предварительный просмотр activity_cheat.xml в альбомной ориентации Листинг 5.2. Заполнение макета второй активности (activity_cheat.xml)
Создание нового субкласса активности 109 android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="24dp" />
110 Глава 5. Вторая активность Рис. 5.7. Создание суперкласса CheatActivity Объявление активностей в манифесте Манифест (manifest) представляет собой файл XML с метаданными, описывающими ваше приложение для ОС Android. Файл манифеста всегда называется AndroidMani- fest.xml и располагается в корневом каталоге вашего проекта. На панели Package Explorer найдите и откройте AndroidManifest.xml в корневом ката- логе проекта. Не обращая внимания на графический редактор, выберите вкладку AndroidManifest.xml в нижней части панели редактора. Каждая активность приложения должна быть объявлена в манифесте, чтобы она стала доступной для ОС. Когда вы использовали мастер новых приложений для создания QuizActivity , мастер объявил активность за вас. Для CheatActivity вам придется сделать это самостоятельно. Включите в файл AndroidManifest.xml объявление CheatActivity (листинг 5.4). Листинг 5.4. Объявление CheatActivity в манифесте (AndroidManifest.xml)
Атрибут android:name является обязательным. Точка в начале значения атрибута сообщает ОС, что класс этой активности находится в пакете, который задается атрибутом package в элементе manifest в начале файла. Манифест содержит много интересной информации, но сейчас мы хотим как можно быстрее организовать работу CheatActivity . Другие части манифеста будут рас- сматриваться позднее. Добавление кнопки Cheat в QuizActivity Итак, пользователь должен нажать кнопку в QuizActivity , чтобы вызвать на экран экземпляр CheatActivity . Следовательно, мы должны включить новые кнопки в layout/activity_quiz.xml и layout-land/activity_quiz.xml В макете по умолчанию добавьте новую кнопку как прямого потомка корневого элемента LinearLayout . Ее определение должно непосредственно предшествовать кнопке Next Листинг 5.5. Добавление кнопки Cheat! в макет по умолчанию (layout/activity_quiz.xml)
112 Глава 5. Вторая активность Листинг 5.5 (продолжение) android:text="@string/cheat_button" />
Передача информации через интенты 113 // Запуск CheatActivity } }); updateQuestion(); } } Теперь можно переходить к запуску CheatActivity Запуск активности Чтобы запустить одну активность из другой, проще всего воспользоваться методом Activity : public void startActivity(Intent intent) Напрашивается предположение, что startActivity(…) является методом класса, который должен вызываться для запускаемого субкласса Activity . Тем не менее, это не так. Когда активность вызывает startActivity(…) , этот вызов передает- ся ОС. А точнее, он передается компоненту ОС, который называется ActivityManager ActivityManager создает экземпляр Activity и вызывает его метод onCreate(…) ОС Android Ваше приложение Рис. 5.8. Запуск активности Откуда ActivityManager узнает, какую активность следует запустить? Эта инфор- мация передается в параметре Intent Передача информации через интенты Интент (intent) — объект, который может использоваться компонентом для вза- имодействия с ОС. Пока что из компонентов нам встречались только активности, но еще существуют службы (services), широковещательные приемники (broadcast receivers) и поставщики контента (content providers).