Приложение может легко обновить само себя – для этого достаточно создать уведомление с Intent’ом, ссылающимся на локальный заблаговременно скачанный на устройство apk файл урлом вида file:///data/data/su.elwood/files/my_app.apk. Пользователь видит, что появилось уведомление, смотрит его, нажимает, и андроид переустанавливает приложение. Данные (файлы в директории /data/data) при этом сохраняются. Единственное, что нужно – дать права read на файл, чтобы шелл андроида смог его прочитать. Весь процесс очень прост. Кто-то даже не поленился и наваял аж целый сервис для этого дела – http://www.auto-update-apk.com/. Отдельной похвалы заслуживает тот факт, что создатели сервиса не пожидились и дали исходный код своей библиотечки. В нём можно покопаться и понять, что нужно сделать для написания аналогичной функциональности.
Собственно,
Операционная система Android может делать с вашим приложением много всякого интересного. Например, пересоздавать Activity при повороте экрана, закрывать Activity, переоткрывать их, вызывать onPause(), закрывать вместе с ними диалоги, убивать процессы и так далее. При работе приложения могут происходить звонки, и Activity может быть уничтожена (и даже процесс может быть убит). Возможных кейсов очень много, и сложно предусмотреть всё и сразу. Обычно программист разумный поступает так: согласно документации и набору проведённых вручную тестов выводятся основные правила (rules of thumb), по которым пишется код, далее этот код обильно сдабривается ассертами и сообщениями в лог в ключевых местах, и потом все проблемы можно диагностировать по падениям приложения на ассертах и полученным стектрейсам. После исследования каждой такой проблемы понимание постепенно улучшается, и программист пишет код уже с учётом обнаруженных потенциальных проблем. Однако это работает только для обычных, часто встречающихся ситуаций. Для сложных или редких юзкейсов повторно воспроизвести баг бывает очень сложно, а по стектрейсу и логам не всегда можно понять, что послужило причиной падения. В таких случаях лучше всего помогают сообщения в логах, которые обозначают места вызова функций. Но расставлять их вручную дико неудобно. Для обычного JVM есть известное решение – инструментирование байткода классов после компиляции с помощью таких инструментов, как AspectJ. Эта штука умеет внедрять указанный код перед, после и даже вместо вызова функций, программисту достаточно задать правила, по которым тулза будет определять, какой код надо модифицировать, а какой – нет. Мы просто можем в местах вызова всех методов писать в лог сообщение о том, какой метод был вызван. Загвоздка заключается в том, что байткод виртуальной машины Dalvik (используемой в Android) она, конечно, не понимает. Но мы-то знаем, что приложения под android собираются в 2 этапа, сначала код компилируется в обычные java class-файлы, а потом уже эти классы конвертируются в файл dex! И уже этот dex запаковывается в apk. Так что если у нас получится вклиниться в процесс сборки между этими этапами, то с большой степенью вероятности всё получится, и мы сможем использовать функциональность AspectJ в андроид приложениях. Я нашел пример, который делает ровно то, что мне нужно, единственной проблемой было то, что он не собирался – там был build.xml старого формата, который уже не работал в современных версиях Android SDK. В общем, пришлось делать самому, и результат я выложил в виде тестового приложения.
Ссылка на проект в Bitbucket: https://bitbucket.org/igor_kostromin/android-wheel-datepicker
Контрол был написан для того, чтобы можно было удобно выбирать дату рождения. Выглядит он вот так:
Поддерживаются 2 локали: английская (дефолтная, “en-US”) и русская (“ru-RU”). По сути, это был эксперимент на тему того, можно ли по-простому выделять куски xml-layout в отдельные user control’ы по аналогии с тем, как это принято в WPF. Оказалось, что это довольно просто, но к сожалению, нужно вручную создавать классы и разметку, причем эта разметка ничем не отличается от разметки обычных view, и перемешивается в папке layouts. То же самое и с идентификаторами элементов управления, хотя, тут наверное есть способ выносить их в отдельные ids.xml файлы, но опять же – придется всё это делать ручками, и потом при необходимости использовать такой контрол в другом проекте нужно будет копировать файлы из разных директорий и следить за тем, чтобы ничего не потерялось. В общем, можно, но неудобно. Хотелось бы нативной поддержки этого механизма аналогично тому, как это сделано в Windows Presentation Foundation. Напомню, там есть класс UserControl – базовый для всех таких compound control’ов (то есть состоящих из других контролов – в терминологии android-разработки) и его можно описывать в XAML, а потом включать его в другие XAML-файлы, причем идентификаторы дочерних элементов хранятся там же. Как правило, такие контролы помещаются целиком каждый в свою папку, и скопировать их для реюза очень просто.
Из технического – что можно было бы улучшить конкретно в этом элементе управления.
1) Добавить возможность задавать специфические свойства этого контрола в XML (Day, Month, Year, VisibleItems)
2) Убрать некоторые свойства, доставшиеся от базового LinearLayout (например, Orientation, которую мы всегда устанавливаем в Horizontal), чтобы их нельзя было задать как в XML, так и в коде
3) Проверить поведение контрола в более сложных сценариях размещения – когда от него ожидают заполнения всей доступной области по горизонтали / вертикали, или доступный размер меньше необходимого.
0