Разные версии JDK на одной машине

Written by elwood

322px-java_logosvgДля взаимодействия с 32-разрядной COM библиотекой через jni4net понадобилось, чтобы приложение запускалось с помощью 32-разрядной JDK. Скачал, поставил, и напоролся на то, что установленная 32-битная версия 1.7_25 полностью заменила все имеющиеся JDK, закинув exe-файлы java.exe, javaw.exe прямо в Windows\System32. А мне хотелось, чтобы по умолчанию работала 64-разрядная версия. И только в определённых приложениях запуск производился с помощью 32-битной JVM. Нашел следующее решение:

  • Удаляем из System32 три exe файла, появившихся после инсталляции 32-битной JDK
  • Устанавливаем JAVA_HOME на 64-разрядную JDK. В Path прописываем путь к директории bin этой же 64-разрядной JDK. Это будет JDK по умолчанию.
  • В приложениях, которые требуют запуска с использованием недефолтной JDK, прописываем следующие строки в скрипт запуска:

    set JAVA_HOME=путь к JDK
    set PATH=%JAVA_HOME%\bin;%PATH%

Вот и всё! Теперь у нас в приложениях, где этих строк нет, будет запускаться дефолтная версия JVM, а в приложениях, которые мы сконфигурировали явно, будет стартовать именно та версия, которую мы прописали.

Swing Data Binding разбор полётов

Written by elwood

binding Озаботился поиском библиотеки для связывания данных в java, чтобы использовать в программировании UI компонентов, наподобие того, как это можно делать в WPF. Нашел библиотеку http://databinding.tornado.no/, попробовал и нашел множество проблем, хотя на первый взгляд она показалась мне вполне подходящей. Проблем оказалось настолько много, что я специально решил их все выписать, чтобы потом при разработке библиотек сверяться с этим чеклистом и проверять свои проекты на соответствие желаемому уровню качества. Итак, поехали.

  1. Нет комментариев.
    С этим всё понятно. Если код библиотеки, пусть даже очень небольшой, не содержит комментариев хотя бы к классам и паблик методам, то сразу возникает вопрос о возможности применять эту библиотеку.
  2. Нет репозитория с кодом на одном из хостингов кода
    Нет единой точки входа для того, чтобы скачать последнюю версию исходников, форкнуть или предложить патч.
  3. Нет лицензии
    Не понятно, можно ли использовать код в своих приложениях.
  4. Нет unit тестов
    Нет гарантии того, что код в основных сценариях работает корректно.
  5. Ошибка при вызове StatusMonitor’a в валидации – clearStatus никогда не вызывается. Вместо него вызывается setStatus(null);
    Это уже первая реальная ошибка. Были бы юнит тесты – этой ошибки бы не было.
  6. Поддерживается только связывание с UI компонентами, нельзя связать 2 произвольных объекта.
    Это чисто моя хотелка насчет байндинга.
  7. UI bridges поддерживают только 1 проперти, что делать, если хочется связаться с UI компонентом, но по другому свойству?
    Тоже хотелка.
  8. Проглатывание исключений в вызове валидатора
    Подозрительный код, здесь могут возникнуть трудноотлаживаемые проблемы.
  9. Не поддерживаются свойства с примитивными типами
    Печаль.
  10. Неочевидные комбинации режимов ONCHANGE, ONBLUR итд (можно установить отдельно режимы для байндинга и для валидации/конвертации, например)
    Проблема плохо продуманного АПИ.
  11. Невозможно получить результат валидации и конвертации отдельно, приходит просто строка
    То же самое.
  12. Неудобный интерфейс StatusMonitor
    Аналогично. Необходимо реализовывать 2 метода, хотя вполне достаточно и одного.
  13. При связывании происходит связь только из source в UI. То есть состояние валидации не инициализируется. Нужно явно вызывать flushUiToModel().
    Ещё одно следствие отсутствия юнит тестов.
  14. Установка model.prop = null не всегда приводит к очистке UI. Бага связана с наличием валидатора и с тем, проходит ли текущее значение валидацию. Хотя по идее от этого не должно зависеть вообще никак.
    И еще одно.
  15. Нет возможности отладить какой-то байндинг (включить логирование например).
  16. Непонятные зависимости от commons-beans и транзитивно еще от commons-logging и commons-collections.
    Зачем мне дополнительные 3 джарника для маленькой либы в 40 килобайт кода ?
  17. Байндинг в сторону модели ВООБЩЕ не работает если задан валидатор ! Просто блокер бага.
    Без комментариев.
  18. Нет поддержки локализации сообщений об ошибках в конверторах и валидаторах.
    Это можно было бы пофиксить патчем, но форкнуть код невозможно. А создавать свой отдельный репозиторий не хочется.
  19. Непонятно, как связывать списки.
    Ещё одна очевидная хотелка.

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, которая лежала под ней в исходном процессе (если таковая, конечно, была).