Category Archives: Android

Android может запустить приложение не со стартовой activity

Written by elwood

Untitled

.. если завершено оно было операционной системой по причине недостатка памяти. В этом случае приложение стартует с последней бывшей видимой activity. Зачем это нужно ? Чтобы убийство процессов было прозрачно для пользователя. Рассмотрим типичную ситуацию: у вас открыто приложение, и в этот момент вам позвонили. Если вы после ответа на звонок обнаружите своё приложение заново запускающимся, вас это не обрадует. В общем, нам надо научиться поддерживать это поведение, так чтобы можно было стартануть приложение с любой Activity. А для того, чтобы адаптироваться к таким вещам, нужно эти вещи уметь воспроизводить. В моём случае сценарий воспроизведения такой:

  • Открываем наше приложение, переходим со стартовой Activity на тестируемую
  • Переходим в окно с уведомлениями (которое выползает сверху) и нажимаем на значок настроек
    Этим мы переходим в системное приложение настроек, которое закрывает наше приложение
  • Убиваем процесс командой
    ps | grep su.elwood | awk '{print $2}' | xargs kill
    ( su.elwood – имя пакета вашего приложения )
    Это можно сделать либо в консоли adb -d shell, либо по ssh, если он у вас, конечно, установлен
    Также понадобится root (в adb shell перед выполнением команды нужно выполнить команду su).
  • Нажимаем кнопку Back на телефоне

Обязательно нужно, чтобы какое-то другое приложение закрывало наше, иначе ОС подумает, что программа упала сама, и при перезапуске стартанёт приложение с основной Activity.

Теперь мы научились воспроизводить это поведение, и можем протестировать наше приложение, пробуя запускать его со всех доступных Activities. Осталось только решить, как обрабатывать такие ситуации программно. Здесь я могу отметить, что помимо введения флагов в некоторое глобальное состояние, можно еще абузить особенность андроида, состоящую в том, что при таком перезапуске ОС запомнит стек Activities, который был на момент остановки процесса. И если при перезапуске с “неверной” Activity вы сделаете finish(), то будет создан экземпляр Activity, которая лежала под ней в исходном процессе (если таковая, конечно, была).

Автообновление Android приложений

Written by elwood

1

Приложение может легко обновить само себя – для этого достаточно создать уведомление с Intent’ом, ссылающимся на локальный заблаговременно скачанный на устройство apk файл урлом вида file:///data/data/su.elwood/files/my_app.apk. Пользователь видит, что появилось уведомление, смотрит его, нажимает, и андроид переустанавливает приложение. Данные (файлы в директории /data/data) при этом сохраняются. Единственное, что нужно – дать права read на файл, чтобы шелл андроида смог его прочитать. Весь процесс очень прост. Кто-то даже не поленился и наваял аж целый сервис для этого дела – http://www.auto-update-apk.com/. Отдельной похвалы заслуживает тот факт, что создатели сервиса не пожидились и дали исходный код своей библиотечки. В нём можно покопаться и понять, что нужно сделать для написания аналогичной функциональности.

Собственно,

https://code.google.com/p/auto-update-apk-client/

самое интересное здесь

Используем AspectJ в Android

Written by elwood

Операционная система Android может делать с вашим приложением много всякого интересного. Например, пересоздавать Activity при повороте экрана, закрывать Activity, переоткрывать их, вызывать onPause(), закрывать вместе с ними диалоги, убивать процессы и так далее. При работе приложения могут происходить звонки, и Activity может быть уничтожена (и даже процесс может быть убит). Возможных кейсов очень много, и сложно предусмотреть всё и сразу. Обычно программист разумный поступает так: согласно документации и набору проведённых вручную тестов выводятся основные правила (rules of thumb), по которым пишется код, далее этот код обильно сдабривается ассертами и сообщениями в лог в ключевых местах, и потом все проблемы можно диагностировать по падениям приложения на ассертах и полученным стектрейсам. После исследования каждой такой проблемы понимание постепенно улучшается, и программист пишет код уже с учётом обнаруженных потенциальных проблем. Однако это работает только для обычных, часто встречающихся ситуаций. Для сложных или редких юзкейсов повторно воспроизвести баг бывает очень сложно, а по стектрейсу и логам не всегда можно понять, что послужило причиной падения. В таких случаях лучше всего помогают сообщения в логах, которые обозначают места вызова функций. Но расставлять их вручную дико неудобно. Для обычного JVM есть известное решение – инструментирование байткода классов после компиляции с помощью таких инструментов, как AspectJ. Эта штука умеет внедрять указанный код перед, после и даже вместо вызова функций, программисту достаточно задать правила, по которым тулза будет определять, какой код надо модифицировать, а какой – нет. Мы просто можем в местах вызова всех методов писать в лог сообщение о том, какой метод был вызван. Загвоздка заключается в том, что байткод виртуальной машины Dalvik (используемой в Android) она, конечно, не понимает. Но мы-то знаем, что приложения под android собираются в 2 этапа, сначала код компилируется в обычные java class-файлы, а потом уже эти классы конвертируются в файл dex! И уже этот dex запаковывается в apk. Так что если у нас получится вклиниться в процесс сборки между этими этапами, то с большой степенью вероятности всё получится, и мы сможем использовать функциональность AspectJ в андроид приложениях. Я нашел пример, который делает ровно то, что мне нужно, единственной проблемой было то, что он не собирался – там был build.xml старого формата, который уже не работал в современных версиях Android SDK. В общем, пришлось делать самому, и результат я выложил в виде тестового приложения.

https://bitbucket.org/igor_kostromin/android-aspectj-demo/