Не забывайте про xhdpi, как про ресурсы в папке drawable-xdpi (мне было бы неприятно видеть картинки в мыле на своем самом продвинутом телефоне), так и про внутренние вычисления в коде, если такие имеются. Все последние телефоны (такие как, например, HTC One X) имеют сверхвысокую плотность точек. Нам было досадно узнать, что на новых девайсах наше приложение работает не так как нужно, поскольку в нашей арифметике случая xhdpi просто не было предусмотрено.
Wednesday, May 23, 2012
Monday, April 2, 2012
synchronized(Boolean)
Читал чужой код, вижу блоки синхронизации по какой-то переменной, и вдруг понимаю, что тип этой переменной - Boolean. То есть смысл переменной в том, чтобы хранить какой-то флажок, а объектом переменная сделана для того, чтобы иметь возможность выполнить по ней синхронизацию. И тут мы проходим мимо здоровенных граблей, который могут нас больно ударить по самому больному месту. Дело в том, что существует всего два объекта Boolean - Boolean.FALSE и Boolean.TRUE. В двух абсолютно не связанных друг с другом кусках кода мы можем иметь по переменной типа Boolean. Эти переменные будут иметь абсолютно разный смысл, но в один момент они могут ссылаться на один объект. И когда мы войдем в блок синхронизации в одном месте программы, другой блок уже не сможет выполниться. И наоборот. Хотя логической связи между ними не будет вообще.
Формально, конечно, Boolean не синглетон. Конструктор у него public, и экземпляров может быть сколько угодно, то есть вместо Boolean.valueOf() мы можем использовать new Boolean(). Но это выглядит как еще больший хак - любой программист заменит конструктор на статический метод Boolean.valueOf(), как рекомендует официальная документация, и незаслуженно получит в лоб. Я не могу придумать ситуацию, где мог бы понадобиться конструктор Boolean и синхронизация по нему.
Как вывод - НИКОГДА не используйте синхронизацию для объектов типа Boolean и, обобщая, для оберток всех примитивных типов (поскольку некоторые объекты могут кэшироваться внутри класса).
Tuesday, December 27, 2011
ListView сохранение положения
Хочется зафиксировать элегантный способ решения проблемы. Есть ListView, отображающий файлы и папочки, по которым можно перемещаться. Заказчик пожаловался, что при возврате на уровень выше (по аппаратной кнопке back) положение списка должно сохраняться. То есть если мы находились на середине списка, где щелкнули по какой-то папочке, то потом мы должны снова оказаться в середине списка.
Первой попыткой наугад было просто сохранить в стеке (в котором хранилось содержимое каждой папочки уровня выше текущего) Y-координату. Сохранить по getScrollY(), восстановить через scrollTo(O, y). Однако обнаружилось, что getScrollY() - это метод View, а не ListView, и соответственно, возвращает он значение, немного другое по смыслу.
Обнаружился соответствующий вопрос на stackoverflow. Выигрышным ответом было выполнить следующее:
// save index and top position
int index = mList.getFirstVisiblePosition();
View v = mList.getChildAt(0);
int top = (v == null) ? 0 : v.getTop();
// ...
// restore
mList.setSelectionFromTop(index, top);
Решения понятное, но слишком уж низкоуровневое. Чуть ниже оказался ответ всего с одним плюсом (уже с двумя):
// Save ListView state
Parcelable state = listView.onSaveInstanceState();
// Restore previous state (including selected item index and scroll position)
listView.onRestoreInstanceState(state);
Вот и все! Вызовы всех более низкоуровневых методов ListView осуществляет уже у себя внутри. Все крайне очевидно и понятно.
Мораль такова, что всегда нужно пытаться мыслить более абстрактно, и не забывать про удобный метод View.onSaveInstanceState().
Wednesday, December 14, 2011
ADT 16
На днях ADT обновился до 16-й версии. Самое значительное изменение - появление Lint, утилиты, которая анализирует Android-проект и выявляет потенциальные баги, находит типичные ошибки раскладок (layouts), неиспользуемые ресурсы.
Раньше для поиска неиспользуемых ресурсов приходилось пользоваться сторонними утилитами (как, например, android-unused-resources), удобство пользования которыми, признаемся, оставляло желать лучшего. Я даже думал написать свою собственную утилиту (отчасти для себя, отчасти для того, чтобы получить плюс в карму за создание и поддержку полезного проекта с открытым исходным кодом :)), не взялся отчасти и от того, что ожидал чего-то подобного от Google, а инициатива от Google убила бы проект на корню. Дождался!
Полноценного анализа java-кода пока не производится, как и не производится анализ связей между проектами (например, ресурсы могут не использоваться внутри библиотечного проекта, но использоваться другими проектами в том же workspace), но, следует полагать, Lint будет только развиваться.
Всем удачного обновления и приятного дня!
Раньше для поиска неиспользуемых ресурсов приходилось пользоваться сторонними утилитами (как, например, android-unused-resources), удобство пользования которыми, признаемся, оставляло желать лучшего. Я даже думал написать свою собственную утилиту (отчасти для себя, отчасти для того, чтобы получить плюс в карму за создание и поддержку полезного проекта с открытым исходным кодом :)), не взялся отчасти и от того, что ожидал чего-то подобного от Google, а инициатива от Google убила бы проект на корню. Дождался!
Полноценного анализа java-кода пока не производится, как и не производится анализ связей между проектами (например, ресурсы могут не использоваться внутри библиотечного проекта, но использоваться другими проектами в том же workspace), но, следует полагать, Lint будет только развиваться.
Всем удачного обновления и приятного дня!
Friday, November 25, 2011
Motorola DroidX - useless HDMI port
http://www.androidpolice.com/2010/07/06/droid-x-hdmi-out-is-crippled-to-play-only-videos-or-display-photos-taken-on-the-device/
http://techcrunch.com/2010/08/30/motorola-droid-xs-hdmi-port-is-only-active-in-gallery-app/
Инженерам Motorola DroidX - пламенный привет. HDMI-выход в этом телефоне работает только тогда, когда вы запустите приложение "Галерея". Пустить изображение-видео из любого другого приложения на экран телевизора не получится. Нет слов.
Еще надо заказчику это объяснить.
Monday, October 24, 2011
Затемнение ImageView по нажатию
Недавно разобрался с такими типами Drawable, как LayerDrawable и StateListDrawable.
Для начала опишу задачу. Есть GridView, каждая ячейка которого представляет собой картинку 80x80. Картинка получается с сервера. Не так давно заказчик захотел, чтобы ячейка представляла собой не просто картинку, а картинку + круговую тень поверх нее, примерно вот такую, чтобы приложение смотрелось немного "гламурнее":
Решение вызывать setImageDrawable в переопределенном методе setImageBitmap на первый взгляд выглядит неудачно и "грязно", но если мы заглянем в исходный код класса ImageView, то мы увидим следующее:Для начала опишу задачу. Есть GridView, каждая ячейка которого представляет собой картинку 80x80. Картинка получается с сервера. Не так давно заказчик захотел, чтобы ячейка представляла собой не просто картинку, а картинку + круговую тень поверх нее, примерно вот такую, чтобы приложение смотрелось немного "гламурнее":
Кроме того, при нажатии на картинку картинка должна была еще затемняться одноцветной черной полупрозрачной маской.
Как это реализовать?
Вручную программно выполнять какие-то наложения картинок не захотелось сразу. Почти сразу решил сделать 3 картинки во FrameLayout, лежащих одна на другой, но после небольшой попытки выполнять соответствующий setVisibility на полупрозрачную маску по событию MotionEvent от этого тоже захотелось отказаться.
Вспомнились селекторы, которые позволяют указать соответствующий drawable элементу в зависимости от своего state - pressed, focused, и др. Но на свойство visibility нельзя повесить никакой selector, что, в принципе, логично. Поиск привел меня к LayerDrawable, которые позволяют создавать один Drawable по слоям из нескольких. Идея свелась к тому, чтобы использовать selector, в котором на pressed state подключать LayerDrawable с тремя вложенными картинками, на обычный state - с двумя.
Однако - сами-то картинки (не декоративные, а информационные) каждый раз разные! Поэтому на чистом xml, при всем желании, реализовать бы все не удалось, поэтому я плюнул, и решил все реализовать программно с использованием уже знакомых LayerDrawable и StateListDrawable (который может реализовать selector прямо в коде).
Получившийся код:
public class ObscuredImageView extends ImageView { protected static final String TAG = "ObscuredImageView"; private Drawable _innerShading; private Drawable _obscured; public ObscuredImageView(Context context, AttributeSet attrs) { super(context, attrs); _innerShading = getContext().getResources().getDrawable(R.drawable.inner_shading); _obscured = getContext().getResources().getDrawable(R.color.semitransparent); } @Override public void setImageBitmap(Bitmap bitmap) { Log.v(TAG, "Going to set state drawable to ImageView"); BitmapDrawable image = new BitmapDrawable(getContext().getResources(), bitmap); Drawable pressed = new LayerDrawable(new Drawable[] { image, _innerShading, _obscured }); Drawable normal = new LayerDrawable(new Drawable[] { image, _innerShading }); StateListDrawable states = new StateListDrawable(); states.addState(new int[] { android.R.attr.state_pressed }, pressed); states.addState(new int[] { android.R.attr.state_focused }, pressed); states.addState(new int[] {}, normal); setImageDrawable(states); } }
public void setImageBitmap(Bitmap bm) { // if this is used frequently, may handle bitmaps explicitly // to reduce the intermediate drawable object setImageDrawable(new BitmapDrawable(bm)); }Так что вызов setImageDrawable абсолютно корректен.
Таким образом, я получил работающее и гибкое решение. Если кто-то реализовал подобное другим образом - с интересом приму к сведению.
Friday, October 21, 2011
Meld Diff Viewer
Не так давно открыл для себя отличную программу под Linux для сравнения файлов и директорий - Meld Diff Viewer. Под Mac OS X, как написано здесь , тоже есть билд, правда, не знаю, насколько он симпатичный по сравнению с билдом из более "родной" среды.
Скриншот:
Уверен, каждый программист найдет ей применение.
Скриншот:
Уверен, каждый программист найдет ей применение.
Subscribe to:
Posts (Atom)