Java Tips | |
Этот сайт посвящен вопросам программирования на Java. Все, что здесь описано, является результатом моих личных экспериментов %) В основном сведения, помещенные здесь, касаются разработки аплетов и MIDP-приложений (J2ME). | |
- Когда вы программируете аплет, у вас будет необходимость часто перезапускать ваш аплет в браузере. Иногда аплет "застревает" в кэше и, что бы вы ни делали, загружается старая версия аплета. Чтобы перезапустить аплет без кэша используйте Ctrl+Shift+Обновить. - В Windows2000 аплеты (а значит и jvm) работают заметно быстрее, чем в Windows9x. - Все объекты java.awt.Graphics необходимо явно освобождать методом dispose(), так как они могут не освобождать занятые графические контексты автоматически. Лучше всего это делать в методе destroy() аплета. Если этого не делать, то после нескольких запусков вашего аплета Windows не сможет создавать новые графические контексты, а значит и рисовать в окнах. - Если вы используете потоки (Threads) создавайте и уничтожайте их в методах start() и stop(). Некорректное создание/уничтожение потоков может привести к тому, что после завершения аплета поток останется в памяти. Код должен быть примерно такой: - Обычно в методе run() потока присутствует цикл do { ... } while (true); Внутри цикла рекомендуется "усыплять" поток на короткие промежутки, иначе он захватывает почти 100% процессорного времени (особенно актуально для windows9x). Не поленитесь перед }while (true); поставить следующее Синхронизация скорости работы аплета 1. Вы определяете, сколько миллисекунд должно занимать выполнение основного рабочего цикла аплета. Предположим вы хотите, чтобы ваш аплет выдавал 35 кадров в секунду, тогда один цикл должен выполняться за 1000/35 миллисекунд. Затем вы засекаете время перед началом выполнения основного цикла (c помощью System.currentTimeMillis()) и после, вычисляете разницу и делаете необходимую задержку. Пример:
Что лучше? Попробуйте сами %) Взаимодействие Java-аплета с JavaScript(JS) Для того, чтобы получить доступ к методам аплета из JS достаточно использовать встроенный массив applets. Например для вызова метода аплета method(): document.applets[0].method(); Предполагается, что на странице первый из аплетов объявлен как <APPLET CODE="some.class" NAME="myapplet" WIDTH=200 HEIGHT=200> </APPLET> Можно передавать какие-либо данные в аплет в качестве параметров вызываемых методов, но я с этим не экспериментировал, попробуйте сами, если хотите %) Можно также обращаться из аплета к методам JS. Для этого необходимо использовать пакет netscape.javascript, который вроде бы входит в стандартную поставку JVM для Windows. Если нет, то его можно скачать где-нибудь. В этом пакете определены два класса - JSObject и JSException. Последний - это исключение, которое генерируется в случае каких-либо ошибок работы экземпляра класса JSObject. Чтобы создать экземпляр класса JSObject необходимо воспользоваться его статическим методом getWindow(Applet ap). То есть JSObject jsGate=JSObject.getWindow(this); После этого можно вызывать любые функции JS используя конструкцию Можно и параметры передавать. Последний пример демонстрирует вызов функции AcceptByte, объявленной в JS: function send(){document.applets[0].acceptObject(document.applets[1].getObject());} Внимание! Такой способ работает только в Java 1. С Java2 плагином вызов такой функции вызывает крушение браузера. Java1.x поддерживает воспроизведение только звуков в формате Sun (*.au). При этом звук должен быть 8KHz 8 битный (вроде бы можно и 16 бит) и моно. - Одна из проблем, общее решение которой я так и не нашел, - загрузка звуков до их первого проигрывания. MediaTracker в Java1.x не поддерживает загрузку звуков. Есть идея загружать звуковой файл как обычный файл побайтно, а потом проигрывать. Предполагается, что файл окажется в кэше. Однако этот способ мне не нравится, даже если он будет работать. Я просто проигрываю критичные звуки еще до начала загрузки изображений. - Вторая серьезная проблема возникает при проигрывании звука в том случае, когда операционная система не может микшировать звук (т.е. если звуковое устройство (ЗУ) занято, то оно недоступно). Дело в том, что JVM проверяет доступность ЗУ только при первом проигрывании звука, а потом проигрывает звуки без проверки. Тогда если после первого проигрывания какое-то приложение займет ЗУ (например пользователь запустил WinAmp), то при попытке проиграть очередной звук аплет повиснет с выдачей 'No audio device' в консоль. Решение состоит в том, чтобы захватить ЗУ и не освобождать его все время, пока работает аплет. Чтобы сделать это, надо создать короткий по времени файл с тишиной и после загрузки аплета проигрыват его методом AudioClip.loop() и останавливать только перед выгрузкой аплета из памяти (AudioClip.stop()). Надо заметить, что поток Audio Player, который проигрывает звуки в JVM, микширует au-файлы без всяких проблем (ну почти). - Для обработки звуковых файлов я пользуюсь Cool Edit Pro.
| |
Сегодня приложения под эту платформу становятся все более популярными. Дело в том, что практически все современные модели телефонов поддерживают J2ME. Сейчас основной тип приложения для J2ME это игры. Приложения для J2ME (мидлеты) позиционируются как кроссплатформенные, но на практике это не совсем так. Проблемы:
Таким образом создать один мидлет для всех устройств, поддерживающих MIDP практически, невозможно. Скорее всего вам придется вносить в код и в оформление мидлета те или иные изменения для того, чтобы он правильно работал на нужной платформе и использовал ее возможности по максимуму. Исходя из всего вышесказанного, разрабатывайте ваши приложения таким образом, чтобы легче было в них потом что-то менять. Общие рекомендации:
Для разработки мидлетов существует огромное количество софта. В любом случае кроме Java 2 SDK и собственно средства разработки вам понадобятся эмуляторы (вариант - SDK) для конкретных моделей телефонов. Лично я пользуюсь софтом от Sun, который доступен для бесплатного скачивания и использования (см.http://wireless.java.sun.com/allsoftware/). Итак, что нужно:
Программирование для платформы Nokia Nokia на мой взгляд является одним из передовых производителей телефонов в плане инноваций (и J2ME в том числе). На рынке телефонов Nokia представлена очень широко и если вы занимаетесь разработкой на J2ME, то под Nokia вам точно программировать придется. Итак приступим ;)
Телефоны Nokia c поддержкой J2ME разделены на серии. В рамках каждой серии есть общие особенности (например размер экрана, общие ограничения на размеры мидлета и памяти и т.п.). Основные серии, для которых выпускаются игры и приложения на J2ME, это Series 40 и Series 60. Телефоны обеих серий имеют цветной экран и позволяют использовать фирменный набор классов от Nokia - Nokia UI, о котором ниже. Телефоны Series 30 на мой взгляд внимания не заслуживают - это старые модели с небольшим черно-белым экраном (кроме 3510i), которых продается все меньше. Series 90 также распространена слабо.
-= Nokia UI =-
Этот набор классов естественно есть только у телефонов Nokia. Основные возможности, которые он дает: Рисование на полный экран Для этого необходимо наследовать вашу "рисовалку" не от Canvas, а от FullCanvas. При этом теряется возможность использовать команды (Command). FullCanvas выбрасывает исключения при попытке добавить команды или CommandListener, зато появляется возможность обработки кнопок экранного меню. В FullCanvas для этого определены константы Возможность работы со звуком Можно делать звуки вроде простой пищалки и даже проигрывать мелодии. Для этих целей нужно создавать объекты класса Sound. Простейший вариант - единичный звук с заданной частотой и длительностью - Естьконструктор
не очень хорошо, так как это засоряет код (попробуйте дизассемблировать и заглянуть в конструктор). Лучше взять строку в шестнадцатеричном формате, разобрать ее, а потом уже использовать. Пример следует ниже. Да, кстати, одновременно может проигрываться только один Sound, мало того, если вы попробуете что-то поиграть, пока предыдущий звук не остановился, могут возникнуть проблемы (Exception хе-хе), хотя вроде как происходить этого не должно. Так что нужно следить за тем, чтобы проигрывался только один звук. Пример:
Не стоит насыщать свои игры звуками (и уж тем более на фон что-то вешать) - будет тормозить.
Дополнительные возможности рисования Для их использования нужно создавать объект классаDirectGraphics:
На DirectGraphics можно рисовать Image'ы с различными манипуляциями (повороты - только на углы, кратные 90 ;), отражения), треугольники, многоугольники, растеризовать массивы (см. ниже) и создавать массивы из изображений, а также устанавливать цвет в формате ARGB (между прочим в 60й серии поддерживается частичная прозрачность, и для Image'в тоже). Для подробностей см. документацию.
Доступ к пиксельной информации изображений Можно создавать массивы из картинок (
Доступ к вибро и свету Осуществляется через статические методы класса DeviceControl. Не забудьте брать их в try...catch! Например на Series40 почти все телефоны поддерживают доступ к вибро, но как оказалось не все. И на том, который не поддерживает, выбрасывается IllegalStateException.
Возможность создания картинок (Image) с прозрачным фоном В DirectUtilsестьметод
Документацию по NokiaUI можно найти на сайте Nokia или вместе с эмулятором в папке docs.
Кроме NokiaUI используются и другие расширения стандарта. Например, это Mobile Media API, которое настоятельно рекомендую использовать вместо NokiaUI, если это возможно.
Теперь глюки %) Глюки попадаются практически в любой реализации J2ME, так что будьте готовы.
Наверняка еще что-то есть, но я сейчас не помню, вспомню - напишу. Сразу, чтобы подчеркнуть важность темы, приведу следующую аксиому: Если вы программируете на J2ME, то вы обязаны использовать обфускатор! Что же это такое? Обфускаторы (от английского obfuscate – сбивать с толку) использовались уже давно для запутывания java кода (class файлов) с целью затруднить их декомпиляцию. Дело в том, что в class файле все имена переменных, классов и т.п. хранятся в первоначальном виде и декомпилированый код практически ничем не отличается от исходного. Обфускаторы меняют все имена (переменных, классов и т.п.) на малопонятные (a, a1, a1_ и т.п.) и запутывают код (каждый по-своему). Это полезно само по себе, но есть еще один невероятно полезный в J2ME побочный эффект – при использовании обфускатора размер класса как правило значительно уменьшается! Можно получить экономию для мидлета в несколько килобайт, а это порой бывает жизненно необходимо. Обфускаторов много, какой из них выбрать – решайте сами. Можно попробовать применять несколько поочередно – эффект бывает как положительный, так и отрицательный. Я расскажу об использовании обфускатора самым тернистым способом – с командной строки – на примере Retroguard. Сам Retroguard поставляется в виде Java-программы, запакованной в Jar архив (retroguard.jar). Итак, командная строка для «обфусцировния» мидлета, написанного для NokiaSeries 40:
Разберем все по порядку. В classpath перечислено следующее:
Откуда берутся последние два класса. emptyapi.zip ищется в SDK для определенного телефона, а если там его нет, то берете его из папки WTKLib вашего WTK (сначала смотрите в WTK конкретного производителя, потом уже если нет, то в Sun’овском). classes.zip – этот берется из папки lib из SDK конкретного телефона. Может называться api.jar, api.zip и т.п. Есть один нюанс – для Series 60 я использую те же API, что и для Series 40, с родными почему-то не хочет обфускиваться. Дальше
После того, как процесс завершен, рекомендую зайти в получившийся архив и удалить из файла манифеста (META-INF/manifest.inf) лишнюю информацию. Дело в том, что ретрогард для каждого файла архива оставляет здесь информацию типа
Видимо для проверки целостности файлов архива. Но в J2ME эта информация лишняя, а для мидлетов под Siemens ее наличие и вовсе приводит к тому, что мидлет не запускается. Кроме того, ее удаление приведет к значительному уменьшению размера мидлета. Так что ее нужно удалить (не удалите лишнего!). Чтобы не мучаться с архиватором JAR, лучше всего поставить плагин 7zip в FAR и просто изменить манифест и автоматически перепаковать архив в режиме normal (уровень компрессии 6). Далее необходимо, чтобы получившийся мидлет прошел преверефикацию. Сделать это можно так:
Здесь classes.zip тот же, что и раньше, а obfuscated.jar – результат обфусциования. То, что получится будет в папке output. Теперь остается переименовать результат в то имя, которое имеет jad файл исходного мидлета (source.jad), а затем зайти в jad файл и поставить в атрибут MIDlet-Jar-Size получившийся размер jar файла. Слишком трудно? %) Есть возможность интегрировать обфускатор в среду разработки (см. например тут) – это просто, но я не пробовал, дерзайте сами. | |
В этом разделе я буду приводить некоторые полезные алгоритмы и формулы, которые в свое время были мне нужны и которые я собственноручно откопал в различных источниках. Все это хозяйство особенно ценно будет для разработчиков игр. Данная формула необходима для того, чтобы иметь зависимость y(x), которая соответствует параболе, проходящей через три заданные точки. Координаты этих точек - (x0,y0),(x1,y1) и (x2,y2).
Применений можно придумать много. Например в одной игре у меня лягушки прыгали с листика на листик по параболе. Делалось это так: первая координата - текущее положение лягушки, третья - то, в которое она попадет после прыжка, а вторая - ((x2+x0)/2;max(y2,y0)+h), где h - высота полета (в данном случае она была отрицательная, т.к. ось oy направлена вниз) в точке (x1,y1). Получались весьма красивые прыжки %) Целочисленный квадратный корень Ниже приводится алгоритм для вычисления квадратного корня из целых чисел с использованием только операций над целыми числами. Как он работает, я, хоть убейте, не понимаю, хотя там, где я его нашел и давалось объяснение.
Целочисленный алгоритм нужен для использования в мидлетах. Типов с плавающей точкой в MIDP нет, а использования такого алгоритма обычно оказывается вполне достаточно. |