Показать сообщение отдельно
Старый 25.06.2015, 17:33   #24
Жека
Дэвелопер
 
Регистрация: 04.09.2005
Адрес: Красноярск
Сообщений: 1,374
Написано 489 полезных сообщений
(для 882 пользователей)
Ответ: Смесь: Неочевидное + Оптимизация

Мы зарелизили новую версию - 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[] = new byte[size];
        
int actual dis.read(b);
        
dis.close();
        
is.close();
        
String s = (new String(b0actual"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;

(Offline)
 
Ответить с цитированием
Сообщение было полезно следующим пользователям:
St_AnGer (14.10.2015)