Метка: программирование

  • Density independent pixel (dp) в Android

    Вопрос про единицу измерения длины “dp” постоянно появляется на различных форумах и сайтах посвященных разработке приложений под ОС Android.
    В большинстве случаев, в качестве ответа более опытные программисты приводят цитату с официального сайта:

    Density-independent pixel (dp)
    A virtual pixel unit that you should use when defining UI layout, to express layout dimensions or position in a density-independent way.
    The density-independent pixel is equivalent to one physical pixel on a 160 dpi screen, which is the baseline density assumed by the system for a “medium” density screen. At runtime, the system transparently handles any scaling of the dp units, as necessary, based on the actual density of the screen in use. The conversion of dp units to screen pixels is simple: px = dp * (dpi / 160). For example, on a 240 dpi screen, 1 dp equals 1.5 physical pixels. You should always use dp units when defining your application’s UI, to ensure proper display of your UI on screens with different densities.

    В целом, мотивы создания dp-единицы описаны довольно ясно. Никому не хочется делать множество различных версток для экранов с разным разрешением и плотностью точек.
    Тем не менее, давайте посмотрим более подробно на указанную выше формулу:

    px = dp * (dpi / 160)

    Здесь главное не запутаться. Если px – это длина в пикселях, а dp – длина в д-пикселях, то для dpi = 240 получится:

    px = (dpi/160) * dp = 1.5 * dp

    По указанной выше формуле получим, что если dp = 1, то px = 1.5.

    Попробуем разобрать ситуацию по существу. Ввод единицы измерения длины dp, нужен был для того, чтобы на экранах с разным количество точек на дюйм размеры графических элементов были одинаковыми.
    Например, если взять экран с 160dpi (160 точек на линейный дюйм) и с 240dpi, то для того, чтобы физический размер кнопки был одинаковый, нужно на экране с 240dpi размер кнопки в пикселях делать в 1.5 раз больше.

    Здесь важно определиться в понятиях размер, разрешение и плотность:

    • Размеры (3”, 10” и т.д.) – физические размеры экрана. В Android-е это разные группы ресурсов: small, normal, large, and extra large. Измеряются в dp.
    • Разрешение (QWGA, HVGA и т.д.) – количество точек на экране (например: 1024×720).
    • Плотность (DPI) – количество точек на линейный дюйм. В Android-е это разные группы: ldpi (low), mdpi (medium), hdpi (high), and xhdpi (extra high).

    Итак понятно, что единица dp – это такой виртуальный пиксель, который на плотных экранах занимает большее количество пикселей, а на разреженных меньше.
    Цель – сохранить единообразие в пользовательском интерфейсе.

    Дальше самое интересное. Чтобы лучше понять, как происходит преобразование dp в px на самом деле, думаю имеет смысл посмотреть в исходный код:
    (далее…)

  • SOAP. Посмотреть конверты.

    Пару простых хинтов для тех, кто начинает изучать работу с SOAP.

    Java 6

    С тех пор как вышел JDK 6 (декабрь 2006г) веб-сервисы стали доступны из “коробки”. В итоге начинать изучение работы с ними стало намного легче, без томкатов, жбоссов, глассфишей и других больших серверов.

    Учебных материалов по работе с веб-сервисами существует огромное количество. В этой статье я хотел только привести два популярных и полезных JVM ключа.

    Дампим отсылку SOAP-сообщения на консоль со стороны клиента:

    -Dcom.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.dump=true
    

    Дампим отсылку SOAP-сообщения на консоль со стороны сервера:

    -Dcom.sun.xml.ws.transport.http.HttpAdapter.dump=true
    

    Прокси

    Другой способ для отладки – использовать прокси.
    Я в работе использую Fiddler. Думаю этот инструмент хорошо знаком большему количеству веб-разработчиков.
    С его помощью можно отслеживать запросы, эмулировать работу на медленных соединениях и т.д.

    Например, если вы работает по SOAP из standalone-приложении (Java 6), то, настроив системные свойства для прокси, можно через Fiddler просматривать что отправляется на самом деле:

    // или -Dhttp.proxyHost= и т.д.
    System.setProperty("http.proxyHost", "localhost");
    System.setProperty("http.proxyPort", "8888");
    // ВАЖНО! Чтобы локалхост не исключил.
    System.setProperty("http.nonProxyHosts", "");
    

    Замечания

    Если вы используете Аxis или какую-то другую библиотеку для работы с SOAP, то естественно настраивать дамп конвертов нужно будет другим способом. В этом плане подход с использованием прокси более универсальный. Тем не менее, изучать способ настройки прокси всё-равно нужно будет под конкретный фреймворк.

  • Про JavaScript (не для JavaScript программистов).

    Последние полтора месяца пишу для одного своего заказчика графический движок на JavaScript (HTML5/Canvas), который будет рисовать в браузере некоторые их инженерные схемы. Параллельно консультирую штатных программистов, у которых не очень большой опыт работы с JavaScript-ом.

    При кажущейся простоте JavaScript не создан для легкого написания надежного кода. Для самопроверки пользуюсь jsLint-ом и периодически запускаю google closure compiler. Тем не менее, это не решает всех проблем. Даже если вы пишете правильный и аккуратный код, указываете комментарии в исходником коде для проверки типов и т.д., все равно приходится время от времени сталкиваться с работами других программистов.

    Из своих “полевых наблюдений” за программистами я понял, что у тех несчастных, которые начинают писать на JavaScript-е после других языков, возникает путанное понимание некоторых фундаментальных понятий этого языка.
    (далее…)

  • Про интерфейс: Map<K,V>

    Недавно от товарища пришел вопрос на засыпку: “Почему в интерфейсe java.util.Map метод get в качестве ключа принимает Object, а метод put использует женерики?”

     
        V get(Object key);
        V put(K key, V value);
    

    Сходу ответить не смог, пришлось разбираться. (далее…)

  • Java Zip + русские буквы в названиях файлов

    Баг №4244499

    Этот баг был зарегистрирован еще в 1999г.
    Проблема была не только с русскими файлами, а например с французскими (как в примере).
    Корни довольно глубокие и существовали серьезные (надеюсь) причины, по которым эту ошибку долгое время не исправляли. В итоге, много-много лет в Java нельзя было сделать простыми штатными средствами zip-архив, который бы содержал файлы с именами не на латинице.

    К сожалению, жизнь такова, что все это время некоторых java-программистов заставляли делать такие zip-архивы. Приходилось использовать например apache-вский commons-compress.

    Использовать очень просто. Алгоритм буквально в два шага: (далее…)

  • Немного об OAuth, Android и Facebook

    OAuth авторизация

    OAuth – по определению означает Open Authorization. Поскольку в английском языке слова аутентификация (authentication) и авторизация (authorization) имеют одинаковое начало auth, то сокращение oauth очень неоднозначное. Эти понятия (авторизацию и аутентифакцию) очень часто путают друг с другом.
    Например OpenID – это система для аутентификации.

    Очень кратко про аутентификацию и авторизацию (т.к. это простые и занудные понятия).
    (далее…)

  • Кофе и программисты

    Мой небольшой обзор разных кофеен.

    Уже больше года веду образ жизни свободного разработчика. Время от времени встречаюсь с такими же как я (программистами, стартаперами). На таких встречах мы, как правило, обсуждаем текущие задачи, пьём кофе, строим планы на будущее, а иногда устраиваем “полевые испытания” – вместе проверяем как работает веб-сервер, тестируем приложения под андроид в суровой реальности, а не в тепличных условиях и т.д.
    За время этих встреч у меня появился свой мини-рейтинг различных кофеен с точки зрения их удобства для программистских тусовок. (далее…)

  • do while false

    “Делать пока ложно”.

    Пару дней назад пытался кратко рассказать товарищу через аську про использование
    do { } while(false); для переписывания длинных ветвящихся if-ов.

    Кратко объяснить не получилось, в итоге решил написать в блоге.

    Метод довольно спорный, хотя и встречается в некоторых авторитетных источниках (например
    в “Совершенном Коде” С. Макконела).

    Идея довольно простая.
    0. Код помещаем в “do { …много_кода… } while(false);” блок. Если что-то не так вызываем break.
    1. Оператор break перекинет нас в конец блока do.
    2. Поскольку указан while(false), то повторного выполнения кода не будет.

    Конечно можно использовать для таких целей исключения, вспомогательные переменные и т.д., но думаю полезно знать и про такой способ, ведь некоторые его используют.
    Обычно он подходит для ситуаций когда идут ветвящиеся проверки if-else, а потом (если все хорошо) делается что-то сложное или важное.

    Примитивный (выдуманный) пример:

            boolean error = false;
            if (x > 10) {
                error = true;
            } else if (x > 0 && x < = 10) {
                y = foo();
                if (y > 0 && y < 10) {
                    error = true;
                } else {
                    x = y;
                }
            } // много if-else кода
            
            if (!error) {
                doSomething(x, y);
            }
    

    С помощью break-ов такой код приобретает более понятный (не для всех!) вид.

        do {
                if (x > 10) {
                    break;
                } 
                
                if (x > 0 && x < = 10) {
                    y = foo();
                    if (y > 0 && y < 10) {
                        break;
                    } else {
                        x = y;
                    }
                }
                // много кода для проверок
                doSomething(x, y);
            } while (false);
    
  • Scala и пустота

    В Scala есть несколько разных сущностей для обозначения несуществующих, пустых или неопределенных объектов.
    Начнем с самого привычного для Java-программистов случая.

    Null

    Null – это trait. Объект null (с маленькой буквы) — это как раз и есть объект типа Null. Он находится внизу иерархии типов в Scala, в противовес AnyRef.
    Благодаря этому вы всегда можете как-бы “занулить” любую ссылку, т.е. присвоить ссылки значение null:

    scala> var x = "String"
    x: java.lang.String = String
    scala> var i = List(3)
    i: List[Int] = List(3)
    scala> i = null
    i: List[Int] = null
    scala> x = null
    x: java.lang.String = null
    

    Null работает только для ссылочных типов, для более общего случая, есть “ничто (Nothing)” .

    Nothing

    Nothing – это тоже trait. Nothing находится на самом дне иерархии типов, в противовес Any. Соответственно, это более общий тип, чем Null и подходит даже для AnyVal объектов (числа, буквы, правда/ложь и т.д.).

    В отличие от Null, Nothing не может иметь экземпляров (на то оно и ничто).
    Другими словами нет аналога null для Nothing.

    Возникает вопрос, где такое самое “нижнее ничто” может использоваться?
    В документации по API можно найти несколько примеров:

    // пакет scala.sys
    def error(message: String): Nothing = throw new RuntimeException(message)
    

    Этот метод никогда ничего не возвращает, поэтому возвращаемый тип Nothing.

    Unit

    Unitкласс, чем-то похоже на void, который используется в Java. В Scala тип Unit применяется тогда, когда нужно показать, что функция возвращает пустое значение (но все-таки что-то возвращает, хоть и пустое).

    Если открыть документацию, то можно увидеть что:

    class Unit extends Any with AnyVal
    

    Внимание! AnyVal, а не AnyRef. Это значит, что Unit это не ссылочный тип ( в отличие от Null). Можно сказать, что Unit-у как бы “ближе по родству” будут числа, буквы и другие примитивные типы (которые тоже AnyVal).

    В отличие от Nothing, Unit повезло больше. Он может иметь свой объект, правда в единственном экземпляре. Он обозначается двумя круглыми скобками: (). Например:

    scala> val u = ()
    u: Unit = ()
    

    Другими словами Nothing уместен тогда, когда функция в принципе ничего не возвращает, а Unit – это когда возвращает, но оно пустое.
    Это отличие существенно. Например результат вызова функции с Unit может быть присвоено (в Java с void такой фокус не выйдет).

    scala> def foo():Unit = {}
    foo: ()Unit
    scala> val u = foo()
    u: Unit = ()
    

    Nil

    Nilобъект, пустой список (extends List[Nothing]).
    Поскольку Nil – это список, хоть и пустой, у него как у любого списка есть метод :: (два двоеточия), с помощью которого удобно создавать списки:

    scala> var x = 1 :: 2 :: Nil
    x: List[Int] = List(1, 2)
    

    Это возможно благодаря тому, что название метода заканчивается на : (двоеточие), в таком случае метод применяется к правому операнду (работает для операторной нотации вызова метода).

    Другими словами, это аналогично вызову: (Nil.::(2)).::(1)

    None

    None – это такой хитрый объект (extends Option[Nothing]) , который используется в случае, если мы хотим получить что-то, например, из Map, а его там нет.

    Например:

    scala> var m = Map(1->2)
    m: scala.collection.immutable.Map[Int,Int] = Map(1 -> 2)
    scala> val n = m.get(100)// ну нет такого элемента
    n: Option[Int] = None
    

    None примечателен тем, что:

    • это объект (т.е. синглтон)
    • это кейс-объект
    • наследуется от Option[Nothing]

    В случае попытки получить значение (вызвав метод n.get()), мы получим исключение:java.util.NoSuchElementException.

    Если у None вызывать метод isEmpty() – мы получим true.

    Поскольку None – объект кейс-класса, то мы можем его “матчить” (сопоставлять по шаблону).

    scala> n match { 
     case Some(x) => println("x:" + x) 
     case None => println("none") 
    }
    

    Если у None вызвать метод toList – мы получим пустой список (т.е. Nil).

    scala> n.toList() == Nil
    res21: Boolean = true
    

    Поскольку None объявлен как extends Option[Nothing], а Nothing – “самое нижнее ничто”, то None может работать с любыми типами (как с ссылочными так и с примитивными).

  • EncryptableProperties и защита от дурака

    Все знают, что не следует хранить в конфигурационных файлах (например properties) критически важную информацию в открытом виде.
    Например логины и пароли от базы данных, почты и т.д.
    Не стоит этого делать, т.к. “случайный” сисадмин или пользователь сможет открыть этот ваш файлик и увидеть пароль.

    С учетом того, что довольно часто пароли придумывают люди, то запомнить их бывает очень просто.
    Более того, некоторые пароли настолько поражают воображение, что их очень сложно забыть. Как правило они выглядят так: 123456, sa, manager и т.д…
    Конечно это личное дело каждого, но выставлять на обозрения такие свои пароли, как-то не совсем прилично.

    Если все-таки нет желания сильно напрягаться и прятать пароли в действительно укромные места, можно довольно просто сделать “защиту от дурака” (чтобы пароль явно не читался).

    Как вариант можно использовать Jasypt. Этот довольно большой проект и его можно использовать и в других целей, но мы будем разбирать простой и конкретный случай: предотвратить хранение паролей в открытом виде в properties файле.
    Главное, что нужно понимать, мы не строим защиту от серьезного злобного хакера, а делаем простую защиту от дурака!

    Для этого: (далее…)