Мы зарелизили новую версию - Galaxy 9.0!
Не сегодня, пораньше. Вчера я уже допилил багфиксы для 9.0.4.
К делу. На некоторых телефонах прога закрывалась сразу при запуске, выдавая NullPointerException.
Включая 2 наших тестовых телефона, и это хорошо - было на чём разбираться. Сроки горели, пришлось с багом релизить.
(Но мы не афишировали обнову сразу, лишь спустя несколько дней), так что не было поголовных апдейтов.
Тем более что это j2me, нет автообновлений.
Жалобы про нулпоинтер, конечно, посыпались в службу поддержки.
Начал разбираться.
Встал вопрос - как это дебажить. В андроиде халява - по шнуру тебе в дебаг сливается стек с ошибкой, видишь откуда корни,
а на j2me хрен, - даже текстом на экран просто так не выведешь,
т.к. при появлении ошибки вылазит системный алерт и ничего не успеешь понять.
В итоге я сделал функцию waitForKey, которая крутит бесконечный цикл, пока не нажмём клавишу.
Благо клавиши обрабатываются в отдельном системном потоке, и мы их можем ловить при наличии бесконечного цикла в главном потоке.
Комбинируя waitForKey с выводом на экран каждого шага загрузки ресурсов, я обнаружил,
что проблема в функции загрузки текста из файла:
public static String loadText(final String path) {
try {
final InputStream is = Utils.class.getResourceAsStream(path);
final DataInputStream dis = new DataInputStream(is);
int size = dis.available();
byte[] b = new byte[size];
int actual = dis.read(b);
dis.close();
is.close();
String s = (new String(b, 0, actual, "UTF-8")).trim();
return s;
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
Изучил её внутренности, вроде всё в порядке, но я выдвинул гипотезу-причину, переделал, но не помогло.
[
гипотеза: некоторые телефоны выдают некорректную длину данных в потоке: int size = dis.available();]
Дальнейший пошаговый дебаг выявил окончательную причину.
Так в чём же тут дело?
Ответ:
Выполнение функции попадало в catch с типом IOException, на строчке закрытия стрима, dis или is - кого именно я выяснять не стал.
Сделал вывод: некоторые телефоны, закрывая DataInputStream, автоматом закрывают и InputStream.
Решение: закрывать стримы в секции finally, оборачивая снова в try...catch....
Попутно узнал, что в конструкции try - catch - finally секция finally выполнится, даже если в try есть досрочный return.
private boolean abcd() {
try {
Midlet.sout("try to do");
return true;
} catch (Exception e) {
Midlet.sout("exception");
} finally {
Midlet.sout("finally"); // этот код выполняется
}
return false;
}