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 через меню параметров.