Комментарии 46
Я тоже недавно начала заниматься разработкой под Android. Многое разумно и нравится, что-то бесит (в частности поворот экрана), но больше всего меня убила бага, которая с Android на связана вообще. Эту беду я откапывал 3 часа:
Собственно, оказалось что Java, будучи языком архи-высокого уровня, не перегрузила оператор == для строк, и сравнивает ссылки. Я понимаю почему в С такая шутка вернула бы false, но от Java не ожидал.
Вывод очень прост, перед тем как учить Android, учите Java)
String s1 = "123";
String s2 = "123";
write(s1 == s2); // false
Собственно, оказалось что Java, будучи языком архи-высокого уровня, не перегрузила оператор == для строк, и сравнивает ссылки. Я понимаю почему в С такая шутка вернула бы false, но от Java не ожидал.
Вывод очень прост, перед тем как учить Android, учите Java)
*начал
да, учите Java! String — это объект же! если хотите сравнить объекты — используйте метод equals(..). Вас, наверное, позабавит ещё такой пример:
Integer a = 127;
Integer b = 127;
Integer c = 128;
Integer d = 128;
System.out.println(a==b);
System.out.println(c==d);
если поймёте, почему в консоль выводится именно то, что выводится — в несколько раз повысите своё знания явы
Integer a = 127;
Integer b = 127;
Integer c = 128;
Integer d = 128;
System.out.println(a==b);
System.out.println(c==d);
если поймёте, почему в консоль выводится именно то, что выводится — в несколько раз повысите своё знания явы
String — это объект же!
Qt / C++:
QString s1 = "123";
QString s2 = "123";
write(s1 == s2); //true
Истинна, и пофиг, что QString объект. Того-же мнения C#, и большинство того с чем я работал.
Другими словами, это не так очевидно, как вы об этом говорите. Перегрузку операторов никто не отменял. И честно говоря, я так и не понял, почему в Java сделано именно так.
Да прям уж в несколько раз:-)
Это азы Java, но с неизменяемостью никак не связано.
1. Если бы строки были изменяемымы (тьфу-тьфу-тьфу), equals и == работали бы так же, как сейчас. Для примера см. java.util.Date.
2. В тех языках, где строки иммутабельны, а == используется для проверки равенства объектов (а не равенства ссылок, как в Java), вернулось бы true.
1. Если бы строки были изменяемымы (тьфу-тьфу-тьфу), equals и == работали бы так же, как сейчас. Для примера см. java.util.Date.
2. В тех языках, где строки иммутабельны, а == используется для проверки равенства объектов (а не равенства ссылок, как в Java), вернулось бы true.
> Как раз поведение в итоге связано, строки везде используются, и если они иммутабельны тогда их легко оптимизировать в JVM, а так как это еще и объекты, то == не работает как в С++.
Поведение == в Java одинаково для всех объектов, независимо от того, мутабельны они или нет. Поэтому мне непонятно, в каком смысле поведение == в приведённом изначально примере связано с их иммутабельностью. Если бы Вы сказали «это связано с тем, что строки — объекты», возражений у меня не было бы.
Насчёт вопроса 1: они ещё нужны при взаимодействии с нативным кодом. И первые версии компилятора вряд ли смогли бы хорошо оптимизировать работу с обёртками.
Насчёт 2 Вы же сами правильно сказали: если бы String можно было расширять, то возможности его оптимизировать сильно уменьшились бы. Плюс потенциальные проблемы с безопасностью и т.д.
Поведение == в Java одинаково для всех объектов, независимо от того, мутабельны они или нет. Поэтому мне непонятно, в каком смысле поведение == в приведённом изначально примере связано с их иммутабельностью. Если бы Вы сказали «это связано с тем, что строки — объекты», возражений у меня не было бы.
Насчёт вопроса 1: они ещё нужны при взаимодействии с нативным кодом. И первые версии компилятора вряд ли смогли бы хорошо оптимизировать работу с обёртками.
Насчёт 2 Вы же сами правильно сказали: если бы String можно было расширять, то возможности его оптимизировать сильно уменьшились бы. Плюс потенциальные проблемы с безопасностью и т.д.
Не поймите меня не правильно. Суть моего комментария сводится к тому, что нужно учить Java, а то будет LOL, как в моем случае.
String s1 = "123";
String s2 = "123";
В этом конкретном случае как раз s1 == s2 будет true. Строка «123» попадет в пул констант и обе переменные s1 и s2 будут ссылаться на одну и ту же строку. Где только про это не написано…
Да, я согласен, что можно решить и подписку и сервис (что кстати еще больше увеличит количество кода). Я не совсем имел в виду что везде надо использовать try/catch (я там как раз и написал что кое-где это некрасиво, но решает проблему). Я больше имел в виду что поломаться может все, даже то на что сразу не подумаешь (системный web browser например), поэтому это надо пытаться учитывать и добавлять дополнительную обработку. А try/catch тут как самый простой (но не всегда самый верный) путь.
пересоздание активити при повороте вполне логично с учетом того, что часто активити используют разные разметки для разных ориентаций экрана. то есть, в таких случаях, при повороте необходимо реинфлейтить интерфейс.
для сложных задач используйте сервисы вместо асинктасков. асинктакс для очень быстрых и легких операций (загрузить одну мелкую картинку к примеру).
«android.view.WindowManager$BadTokenException: Unable to add window — token» у вас вылетает потому что контекст активити, на который ссылается прогресс диалог стал невалидным (активити выгрузилась из памяти). это довольно частая ситуация в системе и она проявляется не только при поворотах. еще входящий звонок, нехватка памяти устройства и еще куча всего. такое надо обрабатывать.
И еще совет вам. Вместо того, чтобы собирать сообщения об ошибках у пользователей, а потом оборачивать их в try/catch, пишите модульные и интеграционные тесты, используйте CI сервера и тестируйте поведение вашего приложения во всех ситуациях, включая повороты, заранее.
для сложных задач используйте сервисы вместо асинктасков. асинктакс для очень быстрых и легких операций (загрузить одну мелкую картинку к примеру).
«android.view.WindowManager$BadTokenException: Unable to add window — token» у вас вылетает потому что контекст активити, на который ссылается прогресс диалог стал невалидным (активити выгрузилась из памяти). это довольно частая ситуация в системе и она проявляется не только при поворотах. еще входящий звонок, нехватка памяти устройства и еще куча всего. такое надо обрабатывать.
И еще совет вам. Вместо того, чтобы собирать сообщения об ошибках у пользователей, а потом оборачивать их в try/catch, пишите модульные и интеграционные тесты, используйте CI сервера и тестируйте поведение вашего приложения во всех ситуациях, включая повороты, заранее.
дак кто против того чтобы разметку экрана поменять при повороте? Пусть layout заново отработает. Но зачем все Activity пересоздавать — вот это вообще не понятно. Так как оно не только UI содержит но и его состояние (ну там например может содержать на каком месте в тексте курсор стоит и т.д.). Я все равно не вижу смысла все пересоздавать.
А про использование сервисов — дак я уже писал. Мне все-лишь надо из базы поднять 10-20 записей на экран. И почему для этого я должен сервис делать и кучу кода писать для этого? По моему — дак это и есть легкая операция.
И вот отказываться от сбора ошибок у пользователей и надеяться что ваши тесты покроют все варианты железа и софта — это уж нет… Сами так делайте. Я против тестов ничего не имею, но это совсем разные вещи и они только дополняют друг друга, а не заменяют.
А про использование сервисов — дак я уже писал. Мне все-лишь надо из базы поднять 10-20 записей на экран. И почему для этого я должен сервис делать и кучу кода писать для этого? По моему — дак это и есть легкая операция.
И вот отказываться от сбора ошибок у пользователей и надеяться что ваши тесты покроют все варианты железа и софта — это уж нет… Сами так делайте. Я против тестов ничего не имею, но это совсем разные вещи и они только дополняют друг друга, а не заменяют.
на новой разметке вашего текста с курсором может уже и не быть. Поэтому на мой взгляд пересоздание обосновано. Особые состояния API позволяет сохранять без проблем.
Я не говорил отказываться от сбора ошибок. Просто если б вы покрыли ваш код тестами, все вышеперечисленные ошибки вы ьы выловили до релиза.
Для вытягивания записей из базы в подобных случаях рекомендую CursorLoader.
Я не говорил отказываться от сбора ошибок. Просто если б вы покрыли ваш код тестами, все вышеперечисленные ошибки вы ьы выловили до релиза.
Для вытягивания записей из базы в подобных случаях рекомендую CursorLoader.
Часто бывает layout абсолютно другой (может даже кнопки другие), а у вас в onCreate к кнопкам listener вешаются. Или вы их предлагаете в onResume делать?
Если у вас не используются разные layout'ы для различных ориентаций экрана, то можно использовать достаточно простой (и неочевидный хак) – в манифесте для активити указать
android:configChanges="orientation|keyboardHidden"
что значит хак и почему неочевидный, если об этом в документации написано .
Потому что просто «orientation» не работает. Хотя, согласно документации, этого должно было бы хватить.
поясните пожалуйста вашу мысль. orientation где? В configChanges у меня всегда прекрасно работало без нареканий.
Я не знаю, что у вас работало, но только что создал новый проект для 2.2. Добавьте в onCreate строку
Log.d("dd", "Activity created");
, в манифест android:configChanges="orientation"
и поменяйте ориентацию в эмуляторе и посмотрите в лог. У меня оно пересоздается.еще screenSize нужен
Несколько общих наблюдений.
1) Не используйте ProgressDialog. Вообще. Он блокирует UI (а если нет, то что будет, если юзер нажмет назад, диалог уйдет, а данных нет и отображать нечего? – user interaction сломан), если вы в фоне что-то грузите, то работать с ним еще неудобнее. Замените его элементом UI вашей активити: надо подгрузить данные – отобразите progress bar, данные подгружены – замените layout на другой, с данными. Используйте индикатор в заголовке окна приложения.
2) Android Annotation реально упрощают жизнь и уменьшают кол-во строк кода. На производительности не сказывается, т.к. они все compile-time. С внедрением их в проект все AsyncTask'и были выброшены.
3) RoboGuice – тут исходя из задачи, но посмотреть стоит.
1) Не используйте ProgressDialog. Вообще. Он блокирует UI (а если нет, то что будет, если юзер нажмет назад, диалог уйдет, а данных нет и отображать нечего? – user interaction сломан), если вы в фоне что-то грузите, то работать с ним еще неудобнее. Замените его элементом UI вашей активити: надо подгрузить данные – отобразите progress bar, данные подгружены – замените layout на другой, с данными. Используйте индикатор в заголовке окна приложения.
2) Android Annotation реально упрощают жизнь и уменьшают кол-во строк кода. На производительности не сказывается, т.к. они все compile-time. С внедрением их в проект все AsyncTask'и были выброшены.
3) RoboGuice – тут исходя из задачи, но посмотреть стоит.
Вот только сегодня прочитал «Getting started» на developer.android.com. Потратил часа полтора. Половина проблем из данной статьи (о повороте экрана, о поддержке фич в разных версиях) там обсуждается. Разве это «подводные камни» — если о них пишут на пятой странице руководства новичка, сразу после создания «Hello world»?
По поводу просто я не согласен. Вот почитайте обсуждение на http://stackoverflow.com/questions/10422697/android-loaders-the-way-to-go.
Чем мне нравится программировать для Андроид (пока что), так это тем, что нет еще громоздких фреймверков, огромных библиотек и т.п. (ну типа там WPF всякого) — процесс ближе к «олдскульной» разработке времен Borland C++ 3.11. Но, думаю, не долго осталось:)
А что касается статьи — подводными камнями это назвать трудно. Даже на «особенности» не тянет, я б сказал — «общеизвестные моменты в разработке под Андроид»
А что касается статьи — подводными камнями это назвать трудно. Даже на «особенности» не тянет, я б сказал — «общеизвестные моменты в разработке под Андроид»
Много шума из ничего
Вы говорите про то, что у пользователя была версия Android 2.1. Но ведь можно в AndroidManifest указать минимальную версию SDK, которую Вы поддерживаете. А если уж поддерживаете 2.1, то мне кажется, что в эмуляторе эту проблему можно было бы увидеть.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Некоторые “подводные камни” разработки под Android