Показаны сообщения с ярлыком Android. Показать все сообщения
Показаны сообщения с ярлыком Android. Показать все сообщения

среда, 27 мая 2015 г.

Https в Android: делаем правильно

To что я опишу ниже - не открытие и не тайна. Это есть даже в официальной документации. Проблема в том, что большинство программистов под Android (и я в том числе) пришли из других, более старых платформ, где проблемы с ssl решались иначе или не возникали вообще.
Например, если сертификат вашего сервера почему-то не в порядке (например он самоподписной), то решение отключить проверку сертификата напрашивается само собой. Такое себе "быстрое решение". В результате вроде бы https и все круто, но на публичном wifi ваш клиент рискует пообщаться по "защищенному" каналу с мошенником. Или, к примеру, вы подключаетесь по ip к своему серверу, а в сертификате прописан домен. Отключаем проверку домена? Давайте не будем спешить. Есть решение которое в "особых" случаях не только не снижает безопасность соединения вашего приложения с сервером но и повышает её до воистину параноидального уровня.

пятница, 24 января 2014 г.

Handler - маленький помошник Android разработчика

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

В кратце android.os.Handler это абстракция позволяющая "выполнять" в указаной очередности другие абстракции - события. А что же такое событие? На реализации событиями являются android.os.Message и обычные Runnable.

Немного по делу. Знакомо CalledFromWrongThreadException? Если да, то runOnUiThread не будет открытием, иначе все впереди:).  Рано или поздно у каждого из нас возникает необходимость обновить views после получения данных которое чаще всего выполняется в другом(не главном) потоке. "AsyncTask!" - скажите вы, "Отлично!" - отвечу я. Что общего между runOnUiThread и AsyncTask? Версия выхода не считается;)
Давайте посмотрим на реализацию в фреймфорке.

Случай №1:

    public final void runOnUiThread(Runnable action) {
        if (Thread.currentThread() != mUiThread) {
            mHandler.post(action);
        } else {
            action.run();
        }
    }

Случай №2. Реализация вызова onPostExecute в AsyncTask:

   private Result postResult(Result result) {
        Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }
    private void finish(Result result) {
        if (isCancelled()) {
            onCancelled(result);
        } else {
            onPostExecute(result);
        }
    }
    private static class InternalHandler extends Handler {
        public void handleMessage(Message msg) {
            AsyncTaskResult result = (AsyncTaskResult) msg.obj;
            switch (msg.what) {
                case MESSAGE_POST_RESULT:
                    result.mTask.finish(result.mData[0]);
                    break;
                .........................
            }
        }
    }

среда, 13 ноября 2013 г.

"Вечный Service" в Android

Когда мы делаем приложения, мы руководствуемся самыми гумаными соображениями. Мы хотим облегчить жизнь нашим клиентам, помочь им, защитить, вооружить против любых проблем этого ужасного мира. Но клиенты почему-то не хотят покоряться нашему мудрому руководству. Закрывают наше приложения, останавливают его, находят в списке "запущенных процессов" через настройки и опять-таки останавливают. Ну, как дети малые, ей-богу ;) Если вы в своей всеобъемлющей мудрости хотите спасти своих клиентов от их самих, вам наверняка прийдётся защититься от их жалких попыток упавлять своим смартфоном. Как же это сделать? Перенести логику в Service, чтобы закрытие приложения не останавливало его работу? Недостаточно. Сделать в нём вечный цикл, вызвать startService() в onDestroy() - тоже. В конце концов эти неразумные существа могут перезагрузить смартфон и мы утратим над ними власть не сможем помогать им. Можно, конечно ловить событие загрузки (и ещё стопицот других системных событий) и поднимать наш сервис. Однако система на то и система, чтобы жить своими, непредсказуемыми событиями, а значит никакой гарантии, что эти события произойдут когда нам нужно, увы, нет. Как же нам быть? Ответ очевиден:

среда, 6 ноября 2013 г.

UDP в Android: как приложения ищут друг друга в сети?

В большинстве случаев говря о передаче данных по сети мы имеем в виду TCP. Для большинства сетевых задач этот протокол лучший, но он вообще-то совсем не единственный. И есть вещи, которые с его помощью делать не удобно. Например: мы знаем порт, но не знаем IP-адреса получателя и нам нужно его найти. Опрашивать все адреса локальной сети по очереди? Жуть... Тут надо бы послать широковещательное сообщение, а для этого мы уже используем UDP. Этот протокол достаточно интересен. Например, мы можем слать сообщения и слушать на одном и том же проту одновременно. UDP при отправке широковещательных сообщений не создаёт соединения в привычном нам смысле. Мы не знаем, доставлено ли получателю наше UDP сообщение. Впрочем нам это и не нужно. Передавать данные мы будем уже по TCP. Итак как же экземплярам нашего приложения искать друг друга?

пятница, 4 октября 2013 г.

Создаём свои всплыващие сообщения в Android

Если вы хотите реализовать свои собственные всплывающие сообщения, которыми можно управлять, то этот пост точно для вас! Вы спросите, а почему не взять уже готовую реализацию Toast, и все дела?  Ответ следующий, да спору нет в эффективности этого класса, но я столкнулся с тем, что мне нужны были такие всплывающие сообщения, для которых можно было бы установить, время жизни, анимацию или например обработать событие по нажатию кнопки, которая размещена в вашем контенте. Вот для этих целей, был и создан класс, который может выполнить все перечисленные возможности в отличии о Toast.

пятница, 7 июня 2013 г.

Делаем собственный компонент для Android-приложений

Если вы уже не в первый раз делаете приложения под Android, то наверняка вас часто посещает чувство дежавю: решение большинства задач вы уже где-то видели, когда-то что-то делали, а порой вам даже удаётся найти старый код и "вклеить" его в новый проект. Если же вы работаете в команде, то "помню я это где-то делал" уже не работает. Нужно систематизировать наработки, держать актуальный репозиторий библиотек. А когда своих и сторонних библиотек становится много, то поневоле начинаешь перебирать их, оставляя те, что лучше и избавляясь от остальных. Как же понять, что лучше? И как сделать такой компонент, который навсегда займёт почётное место в репозитории вашей команды?
Ниже я предложу своё видение критериев оценки библиотек и в качестве бонуса: код весьма полезного и удобного компонента для асинхронной загрузки, кеширования и отображения картинок из сети.

четверг, 22 ноября 2012 г.

Синтез голоса в Android-приложении

Когда мы делаем наши Android-приложения, часто приходится сообщать что-то пользователю. Мы открываем ему AlertDialog, показываем Toast, бросаем сообщения в панель уведомления, сигналим, вибрируем... Вершина этой пирамиды уведомлений - просто сказать то что хочешь от клиента "человеческим голосом".
Голос, само собой, будет не совсем человеческим. Мы его синтезируем. То есть, Google синтезирует, а мы его об этом вежливо попросим.
Конечно, это не единственный спрособ: есть десяток голосовых движков, которые замечательно обходятся без Гугла, но подключать их в своё приложение - отдельная непростая (а порой и недешёвая) задача. Да, для них не нужен Интернет, но если ваше приложение и так его требует, то зачем себя исскуственно ограничивать? ;)

пятница, 26 октября 2012 г.

PreferenceActivity: Простое решение для настроек в Android-приложении

Итак, вы потратили пару недель и массу усилий, чтобы сделать своё Android-приложение. Пора бы уже и публиковать, но тут вспоминаем что не хватает одной мелочи: клиенту негде редактировать свои настройки. Верстать ещё одну форму? Не хочется, заказчик забыл согласовать дизайн да и сроки уже поджимают. Вот бы сделать что-то стандартное, простое с минимумом кода! И ведь это вполне возможно. Просто берём и используем PreferenceActivity.

1. Вот оно, PreferenceActivity:

import android.os.Bundle;
import android.preference.PreferenceActivity;
 
public class PrefsActivity extends PreferenceActivity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.prefs);
    }
}

Совсем просто, не правда ли? Конечно, вся простота опирается на хитрую xml-разметку в файле res/xml/prefs.xml:

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
    <PreferenceCategory
            android:summary="Username and password information"
            android:title="Login information" >
        <EditTextPreference
                android:key="username"
                android:summary="Please enter your login username"
                android:title="Username" />
        <EditTextPreference
                android:key="password"
                android:summary="Enter your password"
                android:title="Password" />
    </PreferenceCategory>
 
    <PreferenceCategory
            android:summary="Login and UI settings"
            android:title="Settings" >
        <CheckBoxPreference
                android:key="checkBox"
                android:summary="On/Off"
                android:title="Keep me logged in" />
 
        <ListPreference
                android:entries="@array/listOptions"
                android:entryValues="@array/listValues"
                android:key="listpref"
                android:summary="Role"
                android:title="You role" />
    </PreferenceCategory>
</PreferenceScreen>

Тут описаны три элемента для ввода данных в двух категориях. Два EditTextPreference, CheckBoxPreference и ListPreference. Первые по клику пользователя покажут поля для ввода, второй и третий соответственно галочку и список. Для списка нужно описать варианты для выбора. Это делаем в файле res/values/array.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string-array name="listOptions">
        <item>Customer</item>
        <item>Freelancer</item>
        <item>Manager</item>
    </string-array>
 
    <string-array name="listValues">
        <item>You are customer</item>
        <item>You are freelancer</item>
        <item>You are manager</item>
    </string-array>
</resources>

Два массива содержат соответственно то что увидит пользователь в списке выбора и то, что запишется в настройки. А в какие ключи SharedPreferences будут сохранены данные, спросите вы? Присмотритесь-ка к первому из xml приведённых тут. У каждого элемента есть атрибут android:key. Это и есть тот ключ, в который система сохранит настройки. Заметьте, без всякого нашего участия.

2. Наслаждаемся результатом:

Теперь сделаем главное Activity приложения, откуда будет вызываться окно настроек и куда мы выведем сохранённые настройки, чтобы проверить результат:

import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
 
public class MyActivity extends Activity {
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
 
    public void setPrefs(View v) {
        Intent intent = new Intent(this, PrefsActivity.class);
        startActivity(intent);
    }
 
    public void showPrefs(View v) {
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
        String username = prefs.getString("username", "Anonymous");
        String passw = prefs.getString("password", "Not set");
        boolean checkBox = prefs.getBoolean("checkBox", false);
        String listPrefs = prefs.getString("listpref", "Not set");
        StringBuilder builder = new StringBuilder();
        builder.append("Username: " + username + "n");
        builder.append("Password: " + passw + "n");
        builder.append("Keep me logged in: " + String.valueOf(checkBox) + "n");
        builder.append("Role: " + listPrefs);
        ((TextView) findViewById(R.id.prefs)).setText(builder.toString());
    }
}

Разметка для него:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="fill_parent"
              android:layout_height="fill_parent"
              android:orientation="vertical" android:gravity="center_horizontal" android:paddingTop="30dp">
 
    <Button
            android:id="@+id/btnSetPrefs"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Edit Preferences" android:onClick="setPrefs"/>
 
    <Button
            android:id="@+id/btnShowPreferences"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Display preferences" android:onClick="showPrefs"/>
 
    <TextView
            android:id="@+id/prefs"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
 
</LinearLayout>

И результат, после перехода к настройкам, ввода их, возврата и нажатия на кнопку Display preferences:



вторник, 31 июля 2012 г.

PhoneGap: используем чужие плагины и пишем свои

Предыдущий мой пост о PhoneGap был рассчитан на начинающих разработчиков для мобильных устройств. Теперь давайте обсудим, какую пользу из этого фреймворка могут извлечь те, кто уже умеет делать "настоящие" Android (IOS и т.п) приложения.
Если вам приходилось работать над сравнительно большим приложением в тесном контакте с заказчиком, то вы знаете, какой процент требований заказчик выставляет "вдогонку", после утверждения ТЗ. Можно долго обсуждать, насколько это неприятно и неправильно, но с этим, как правило, приходиться жить. Большинство таких "дополнительных" требований касается того, что заказчик видит, т.е. интерфейса: "Тут сделайте жирным, а вот это подвиньте...". Здорово было бы, чтобы эту малоприятную работу делали не суровые java(objective-C)-программисты, а обычные html-css верстальщики, которых, кстати, нанять легче и дешевле. Таким образом приложение с помощью PhoneGap можно сделать не только кроссплатформенным, но и "двухслойным". Интерфейс и навигацию делаем на HTML5, а "тяжёлую" логику, если она есть, делаем нативной. При этом основной разработчик освобождается от вёрстки xml layout-ов, что само по себе уже даёт существенный прирост его производительности.
На выходе получаем вполне здоровый производственный процесс: html-css-javacsript-программисты пишут приложение на PhoneGap, а за всякой нетривиальной задачей обращаются к плагинам, которые пишут "настоящие" Android-разработчики. Вот давайте и посмотрим, насколько легко можно писать и использовать плагины для PhoneGap.

суббота, 28 июля 2012 г.

Поддержка управления в Android с помощью жестов.

Жесты - один из важнейших способов ввода в Android устройствах. Существует несколько категорий жестов, основные из которых это SingleTouch и Multitouch. 

Одной из желанных "плюшек" в приложении, так или иначе связанным с  изображениями является их масштабирование.

Под масштабированием будем понимать жесты трансформирующие наше View, и использующие более одного касания (мультитач).

Основой для приложения будет класс ScaleGestureDetector,  основной задачей которого является "узнавание" жестов масштабирования, и уведомления приложения с помощью CallBack'ов. При его использовании необходимо учитывать, что данная возможность доступна с версии Android 2.0 (Froyo).

Начнем с создания собственного ImageView.

четверг, 26 июля 2012 г.

PhoneGap: пишем для Android на Html и JavaScript


Разработка для мобильных платформ становится всё популярнее, затягивая всё больше программистов из смежных отраслей. Если вы писали, к примеру, серверный Java-код, то проблем с освоением платформы Android у вас скорее всего не будет. А если "в прошлой жизни" вы делали сайты на html+css+javascript? Тут нужно не только учить новый язык, но и осваивать "настоящее" ООП, которое не сразу и не каждому даётся. Если же вы решили охватить и IPhone/IPad, то учить нужно ещё и Objective-C. Что же делать, если учить новые технологии некогда, а подарить миру своё приложение для смартфонов хочется уже сейчас?
Фреймворк PhoneGap помогает решить эту проблему. Пишите приложение как локальную веб-страницу, а доступ к возможностям смартфона предоставит PhoneGap. Тут я постараюсь дать пошаговое руководство, как сделать простое Android-приложение на Html и JavaScript с помощью PhoneGap. Писать будем в IntelliJ IDEA. Эта замечательная IDE в последнее время сумела выбросить Eclipse из моего компьютера :)
Итак, приступим. Тут будет много скриншотов: лучше один раз увидеть, чем один раз прочитать.

среда, 25 июля 2012 г.

Используем фрагменты в приложении для Android 2.х

Разработчики Android основательно поработали над тем, чтобы наше приложение нормально выглядело как на десятидюймовом планшете, так и на смартфоне с экраном в 3,5 дюйма. Мы можем использовать несколько наборов графики, разные варианты разметки интерфейса в зависимости от ориентации экрана. И компоновать эти интерфейсы мы можем из произвольного набора автономных фрагментов. Конечно, фрагменты поддерживаются начиная с четвёртой версии Android, но с помощью android 4 support library и небольшого танца с бубном, можно реализовать эту технологию и под Android 2.х.
Давайте сделаем небольшое приложение "на фрагментах".

пятница, 20 июля 2012 г.

Распознаём QR-код в Android-приложении

Ранее я писал о том, как сгенерировать QR-код в Android-приложении. Для полноты картины не хватает ещё примера, как распознать QR-код. Простое решение для этого есть: вызвать с помощью Intent какое-нибудь из "посторонних" приложений, использующих ZXing. Эта библиотека предоставляет набор классов и ресурсов для отображения Activity c preview, самостоятельно распознаёт код и возвращает его в ваш метод onActivityResult.
Но как быть, если мы не хотим раскручивать чужие приложения? И встраивать к себе Activity и килограмм ресурсов из клиентской библиотеки ZXing не хочется... Выход есть. Мы можем самостоятельно реализовать всё что нам нужно, используя только ZXing core библиотеку. Давайте посмотрим, как это сделать.

воскресенье, 15 июля 2012 г.

Реализация Drag and Drop в Android

Touch-интерфейсы дают нам удивительную возможность "прикоснуться к приложению", манипулировать с элементами на экране самым естественным для человека способом. И нам, разработчикам, грех не использовать такую возможность. Давайте разберёмся, как максимально просто реализовать Drag&Drop в нашем приложении.
В двух словах уточним, какое поведение элемента интерфейса мы хотим получить. Есть пара белых ImageView и один синий прямоугольник. Та из белых картинок, которой мы коснулись будет следовать за пальцем, пока мы её не отпустим. Если мы отпустим её над синим прямоугольником, прямоугольник станет красным, и картинка останется на месте. Если за пределами - картинка вернётся на исходную позицию.
Основная наша цель - сделать всё максимально просто. Кроме Layout-a, описывающего начальное состояние интерфейса, мы напишем всего один класс в сотню строк кода. Итак приступим.

четверг, 21 июня 2012 г.

Генерация QR-кода в Android-приложении

Недавно познакомился поближе с замечательной технологией: QR-кодами. Простая вроде бы вещь, а какой простор для фантазии открывается! Тут тебе и обмен ссылками между Android-устройствами, передача контактов, своей "визитки", авторизация... Впрочем, оставляю вам придумать свою идею самостоятельно, а пока вы думаете, покажу как работать с QR-кодами программно. Напишем свой простенький генератор QR-кодов. Сделать это совсем несложно: приложение, скриншот которого вы видите справа, я сделал примерно за 10 минут.
Работу этого приложения вы, кстати, можете проверить тут же: просто наведите на скриншот любой сканер QR-кодов и сравните полученную сторку с тем, что введено в EditText вверху.
Итак, приступим.

понедельник, 18 июня 2012 г.

Добавляем к Android-приложению стили Android 4

Ничто так не портит настроение программиста, как необходимость заниматься вместо программирования чем-то другим. Например, дизайном. Но приложение без дизайна в наше время  обречено на забвение избалованных пользователей. Как же быть? А давайте нашим формам и кнопочкам "выдадим" стандартный стиль Android Ice Cream Sandwich. Пусть наши пользователи, которые пока ещё не обновились до последней версии Android наслаждаются стильным дизайном и проникаются к нашему приложению тёплыми чувствами. В этом добром деле нам поможет библиотека HoloEverywhere. Использовать всю библиотеку мы не будем, нам хватит и одной темы, например моей любимой HoloEverywhereDark. А прикрутим к проекту мы её ручками, попутно изучив механизм "стилизации" Android-приложений.

вторник, 12 июня 2012 г.

Новая версия AndEngine GLES2: продолжаем делать игры для Android


Раньше я писал о том, как легко и быстро можно сделать игру для Android c помощью замечательного 2D игрового движка AndEngine и его "физического" расширения box2D. С тех пор многое изменилось в нашем непостоянном мире. AndEngine теперь поддерживает OpenGL ES2.0, и в связи с этим существенно изменилось его API. Можно, конечно продолжать использовать предидущую версию, но если учесть внушительный список изменений, то такой путь выглядит тупиковым.
Как же быть начинающему разработчику Android-игр, если прочитав несколько руководств и создав своё BaseGameActivity он не увидит там больше описанных везде абстрактных методов onLoadEngine, onLoadResources, onLoadScene, onLoadComplete? Ответ простой: читать этот пост и погружаться в разработку игр с использованием новой версии AndEngine GLES2 :)

четверг, 24 мая 2012 г.

Использование websoсket в Android

Самые интересные Android-приложения, по-моему, те, которые позволяют взаимодействовать пользователям на различных устройствах. Например, сетевые игры, коммуникационные и социальные приложения. В разработке таких программ мы должны использовать широкий спектр технологий, и, соответственно, имеем большой простор для творчества, для построения интересной архитектуры.
Я уже описывал некоторые своеобразные решения для клиент-серверного взаимодействия в мобильных приложениях, но сегодня мы познакомимся, вроятно, с самым интересным инструментом для решения таких задач: с технологией websocket.
В чём её прелесть? Практически полный реалтайм, минимальные накладные расходы на передачу данных, возможность реализовать любой, даже бинарный протокол "внутри" websocket-а, и самое приятное: простота реализации и готовые библиотеки. С этим давайте и разберёмся подробнее.

вторник, 22 мая 2012 г.

Играем с акселерометром в Android

И ещё одно замечательное устройство в нашем Android-девайсе дождалось своего примера использования. Использование акселерометра занимает особое место в приложениях (особенно в играх) для Android. Камерой и микрофоном мы могли бы пользоваться и в ноутбуке, а вот этим устройством - вряд ли. Только смартфоном можно размахивать из стороны в сторону в игровом процессе, и тут не обойтись без снятия данных с датчика ускорения. Сам процесс получения данных с акселероматра очень прост и не заслуживает отдельной статьи, поэтому мы сделаем небольшую игру, построенную на использовании акселерометра.
Принцип игры будет заключаться как раз в "размахивании" смартфоном: нужно будет махнуть сильнее чем противник, желательно не разбив аппарат при этом ;)
Как и у всякой приличной игры будет возможность сохранить свои достижения и т.п. Итак, приступим:

понедельник, 14 мая 2012 г.

BroadcastReceiver: общение процессов в Android-приложении

Давайте снова вернёмся к вопросу организации работы фоновых процессов в Android-приложении. В этой статье я описал, как выполнять загрузку файлов с удалённого сервера в фоне. Задача замечательно решается с помощью AsyncTask, но только в случае небольших файлов и недолгого ожидания. Что произойдёт в случае если файл будет загружаться двадцать минут? Телефон уснёт, вы воспользуетесь другим приложением и т.п. - в любом случае загрузка будет прервана. Решение тут очевидно: заменить AsyncTask сервисом, который может работать и без основонго приложения. В случае же использования WakefulIntentService мы практически гарантировано докачаем наш файл несмотря ни на что. И только одну проблему остаётся решить для получения окончательной победы разума над материей: обновлять прелоадер нам нужно в Activity, которая недоступна из сервиса. Выход: использовать внутренний механизм платформы для обмена сообщениями между отдельными компонентами нашего приложения.
Итак, давайте переработаем наше приложения для загрузки файлов так, чтобы оно могло докачать файл при любых обстоятельствах. Научимся использовать BroadcastReceiver.