Статьи

Начало работы с проектами библиотек Android, часть 2

Google предлагает проекты библиотек Android в качестве способа управления повторно используемым кодом. В первой части этой серии из трех статей о проектах библиотек Android я познакомил вас с основами библиотечных проектов.

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

Я использовал Android SDK Release 20 вместе с платформами Android 2.3.3 (API Level 10) и Android 4.1 (API Level 16) для разработки и тестирования кода этой статьи.

О диалоговом окне Android Library Project

Диалоговое окно about (также известное как info) является хорошим примером повторно используемого кода, который можно сохранить в проекте библиотеки Android. О диалоговых окнах обычно идентифицируют приложения (имена, номера версий, значки) и их авторов, предоставляют адреса электронной почты и другие ссылки для получения поддержки и посещения веб-сайтов авторов приложений, предлагают информацию о лицензии / отказе от ответственности и так далее.

Прежде чем я начал разрабатывать эту библиотеку, я размышлял над различными архитектурными вопросами. Каков минимальный уровень API библиотеки и имя пакета? Какие классы и другие ссылочные типы являются частью библиотеки? Я создаю экземпляры классов или отношусь к ним как к одиночкам? Что такое открытый интерфейс каждого типа? Храню ли я ресурсы и код? Если да, то какие ресурсы будут храниться? Я пришел к выводу со следующими ответами:

  • Минимальный уровень API равен 10, так что библиотека может использоваться Android 2.3.3 и выше. Имя пакета будет ca.tutortutor.about .
  • Библиотека будет состоять из одного класса с именем About .
  • About будет служить как синглтон (также известный как служебный класс). Я не буду создавать экземпляр этого класса, но буду вызывать статические методы. В конце концов, приложения обычно представляют одно диалоговое окно.
  • About будет отображать единственный public static void show(Activity activity, String aboutText, String okButtonText) . Этот метод будет использовать диспетчер пакетов Android для получения номера версии приложения, значка и имени.
  • About связан с ресурсом макета; других ресурсов нет. Я решил не включать строковые ресурсы, чтобы упростить локализацию. Я бы предпочел не обновлять проект библиотеки для поддержки дополнительных локалей. Вместо этого я считаю, что локализация должна происходить на уровне приложения; приложение должно передавать локализованный текст в диалоговое окно about.

Изучение исходного кода и ресурсов

Проект библиотеки диалогового окна about состоит из одного исходного файла ( About.java ) и одного файла ресурсов ( ca_tutortutor_about.xml ). В листинге 1 представлены About.java .

 package ca.tutortutor.about; import android.app.Activity; import android.app.AlertDialog; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.graphics.drawable.Drawable; import android.text.Html; import android.text.method.LinkMovementMethod; import android.view.InflateException; import android.view.LayoutInflater; import android.view.View; import android.widget.TextView; public class About { public static void show(Activity activity, String aboutText, String okButtonText) { String versionNumber = "unknown"; Drawable icon = null; String appName = "unknown"; try { PackageManager pm = activity.getPackageManager(); versionNumber = pm.getPackageInfo(activity.getPackageName(), 0) .versionName; icon = pm.getApplicationIcon(activity.getPackageName()); ApplicationInfo ai = pm.getApplicationInfo(activity.getPackageName(), 0); appName = (String) pm.getApplicationLabel(ai); if (appName == null) appName = "unknown"; } catch (NameNotFoundException e) { } View about; TextView tvAbout; try { LayoutInflater inflater = activity.getLayoutInflater(); about = inflater.inflate(R.layout.ca_tutortutor_about, null); tvAbout = (TextView) about.findViewById(R.id.ca_tutortutor_aboutText); } catch(InflateException e) { about = tvAbout = new TextView(activity); } tvAbout.setText(Html.fromHtml(aboutText)); tvAbout.setMovementMethod(LinkMovementMethod.getInstance()); new AlertDialog.Builder(activity) .setTitle(appName+" "+versionNumber) .setIcon(icon) .setPositiveButton(okButtonText, null) .setView(about) .show(); } } 

Листинг 1: About.java

В листинге 1 показан класс About с public static void show(Activity activity, String aboutText, String okButtonText) классом public static void show(Activity activity, String aboutText, String okButtonText) :

  • activity содержит ссылку на вызывающую активность, которая обычно является основной.
  • aboutText содержит текст диалогового окна about, который может включать теги HTML, такие как <b> (полужирный), <i> (курсив), <u> (подчеркивание) и <p> (абзац). Здесь вы можете указать свой веб-сайт для получения поддержки, предоставить информацию о лицензии / отказе от ответственности и т. Д.
  • okButtonText содержит текст, который появляется на кнопке, закрывающей диалоговое окно.

Этот метод сначала получает менеджер пакетов для доступа к номеру версии приложения, значку и имени. Диспетчер пакетов описывается классом PackageManager , доступ к которому осуществляется путем вызова унаследованного PackageManager getPackageManager() метода PackageManager getPackageManager() .

PackageManager объявляет PackageInfo getPackageInfo(String packageName, int flags) для получения информации из пакета приложения. Пакет получается путем вызова унаследованного String getPackageName() метода String getPackageName() .

PackageInfo объект PackageInfo обеспечивает доступ к информации о пакете через его поля. Например, versionName содержит строковое имя версии этого пакета (например, 1.0 ), как указано в androidmanifest.xml <manifest> тега versionName .

Drawable getApplicationIcon(String packageName) позволяет получить значок приложения в виде экземпляра Drawable . Этот метод вызывается с именем пакета действия в качестве аргумента.

getApplicationIcon() ищет значок, указанный атрибутом icon тега <application> , возвращая значок по умолчанию, когда он не находит этот атрибут.

Название приложения теперь получено. Во-первых, ApplicationInfo getApplicationInfo (String packageName, int flags) для возврата объекта ApplicationInfo , соответствующего тегу <application> манифеста. Затем этот объект передается в качестве аргумента в CharSequence getApplicationLabel(ApplicationInfo info) , который возвращает значение атрибута метки тега <application> или значение NULL, если этот атрибут отсутствует.

getPackageInfo() и getApplicationInfo() могут getApplicationInfo() . Прежний метод вызывает это исключение, когда пакет с данным именем не может быть найден в системе. Последний метод вызывает это исключение, когда приложение с данным именем пакета не может быть найдено в системе. Из-за возможности этого исключения versionName , icon и appName инициализируются значениями по умолчанию перед appName этих методов.

Следующая основная задача в листинге 1 состоит в том, чтобы ca_tutortutor_about.xml содержимое ca_tutortutor_about.xml (описывается в ближайшее время) и получить доступ к его раздутому виджету textview. Он получает инфлятор компоновки, вызывая LayoutInflater getLayoutInflater() , и использует этот метод для накачки XML-файла в представление about . Затем он использует для доступа к виджету текстового представления этого представления. Обратите внимание на префикс ca_tutortutor_ в каждом из R.layout.ca_tutortutor_about и R.id.ca_tutortutor_aboutText чтобы избежать конфликтов ресурсов.

Виджет textview теперь настроен. Сначала содержимое aboutText преобразуется из HTML в текст путем вызова метода класса Spanned fromHtml(String source) Html , и результат присваивается текстовому представлению для отображения. Во-вторых, этому виджету назначен метод перемещения ссылки, поэтому нажатие на ссылку приводит к тому, что пользователь попадает в пункт назначения ссылки. (В эмуляторе нажатие на ссылку электронной почты приводит к появлению диалогового окна « Неподдерживаемое действие ».)

Последняя задача — создать экземпляр AlertDialog настроить и показать этот экземпляр. Для удобства я использую вложенный класс Builder AlertDialog для выполнения этих задач.

В листинге 2 представлен ca_tutortutor_about.xml .

 <?xml version="1.0" encoding="utf-8"?> <scrollview xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/ca_tutortutor_aboutView" android:layout_width="fill_parent" android:layout_height="fill_parent"> <linearlayout android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="fill_parent" android:padding="5dp"> <textview android:id="@+id/ca_tutortutor_aboutText" android:layout_width="wrap_content" android:layout_height="fill_parent"></textview> </linearlayout> </scrollview> 

Листинг 2: ca_tutortutor_about.xml

В листинге 2 описан макет, состоящий из вида scrollview, в который вложен линейный макет, в который вкладывается textview. Представление прокрутки присутствует, так что вы можете указать столько содержимого, сколько вам требуется для диалогового окна about, и разрешить пользователю доступ к этому содержимому с помощью прокрутки.

Каждому из scrollview и textview назначается идентификатор, чтобы к нему можно было получить доступ из About.java show() About.java , о котором вы узнали ранее в этой статье. ca_tutortutor_ необходимы для избежания конфликтов ресурсов.

Создание и инициализация О

Давайте создадим и инициализируем этот библиотечный проект. Первым шагом является создание проекта. Я использовал следующую командную строку для выполнения этой задачи на моей платформе Windows:

 android create lib-project -t 1 -p C:\prj\ap\About -k ca.tutortutor.about 

Цель 1 идентифицирует Android 2.3.3 на моей платформе. (Выполните android list targets чтобы получить эквивалентное число целей на вашей платформе.) Я храню этот проект в своем C:\prj\ap\About . Наконец, имя пакета проекта — ca.tutortutor.about .

Затем я создал иерархию подкаталогов ca\tutortutor\about About\src и скопировал файл About.java содержащий содержимое листинга 1, в about . Я также скопировал файл ca_tutortutor_about.xml содержащий содержимое листинга 2, в файл About\res\layout .

About\res\layout также содержит файл main.xml , который помещается в этот каталог при создании проекта библиотеки. Вы можете удалить этот файл или оставить его, потому что проекты вашего приложения, скорее всего, предоставляют свои собственные файлы main.xml , которые переопределяют этот main.xml .

Точно так же вы найдете каталог About\res\values содержащий strings.xml . Поскольку удаление этого файла не позволяет вам создавать About (для проверки любых изменений исходного кода на наличие ошибок), вы можете также оставить этот файл в покое — он переопределяется файлом strings.xml проекта приложения.

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

 ant debug 

Вы должны наблюдать сообщение BUILD SUCCESSFUL .

Вывод

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