Руководство по интерфейсу андроид

В конце декабря 2021-го Android обновил рекомендации по архитектуре мобильных приложений. Публикуем перевод гайда в пяти частях:

Обзор архитектуры

Слой UI (вы находитесь здесь)

События UI

Доменный слой

Слой данных

UI отображает данные приложения на экране: это основное место взаимодействия с пользователями. Если отображаемые данные меняются — из-за взаимодействия с пользователем (например, нажатия кнопки) или внешнего воздействия (например, отклика сети) — UI должен обновиться и отразить изменения. По сути UI – это состояние приложения, полученное из слоя данных и представленное визуально.

Данные приложения из слоя данных обычно отличаются по формату от отображаемой информации. К примеру, для UI может требоваться только часть полученной информации или понадобится объединить два класса DataSource, чтобы отобразить нужную пользователю информацию. Вне зависимости от выбранной логики, пользовательскому интерфейсу нужно передать всю информацию для полной отрисовки экрана. Слой UI преобразует изменения данных приложения в формат, удобный для отображения на UI, а затем отображает эти данные на экране.

Роль слоя UI в архитектуре приложения

Роль слоя UI в архитектуре приложения

Разберём простой пример

Представим приложение с новостями: оно показывает экран со статьями. Если пользователь вошёл в систему, он может добавлять интересные материалы в закладки. Статей много, поэтому у читателя должна быть возможность фильтровать их по категориям.

Таким образом, приложение позволяет пользователям:

  • Просматривать доступные для прочтения статьи.

  • Фильтровать их по категориям.

  • Войти в систему и добавить интересные статьи в закладки.

  • Пользоваться премиальными фичами, если к ним есть доступ.

Пример новостного приложения для изучения UI

Пример новостного приложения для изучения UI

В следующих разделах будем использовать это приложение как пример. Вы познакомитесь с принципами Unidirectional Data Flow (UDF) и узнаете, с какими проблемами в контексте архитектуры приложения в слое UI они помогают разобраться.

Архитектура слоя UI

Под термином UI подразумеваются UI-элементы (например, Activity и Fragment), которые отображают данные: вне зависимости от того, какими API они пользуются для этой цели — View или Jetpack Compose. Цель слоя данных — хранить данные приложения, управлять ими и открывать к ним доступ. Поэтому слой UI должен:

  1. Принимать данные приложения и преобразовывать их в данные, которые UI легко сможет отрисовать.

  2. Принимать данные, которые может отрисовать UI, и преобразовывать их в элементы UI, которые будут показаны пользователю.

  3. Принимать события о вводе данных пользователем от элементов UI из пункта 2 и отражать в данных UI изменения, которые они вносят.

  4. Повторять шаги 1–3 необходимое количество раз.

В следующих разделах этого гайда вы узнаете, как реализовать слой UI, чтобы он выполнял все эти шаги. В частности, этот гайд затрагивает следующие задачи и концепции:

  • Как описать UI-состояние.

  • UDF: как с его помощью создать UI-состояние и управлять им.

  • Как открывать доступ к UI-состоянию с помощью данных типа observable в соответствии с принципами UDF.

  • Как реализовать UI, который принимает UI-состояние типа observable.

Самая базовая из этих задач — описание UI-состояния.

Как описывать UI-состояния

Вернёмся к примеру: UI показывает список статей и метаданные для каждой из них. Информация, которую приложение показывает пользователю, и есть UI-состояние.

UI – то, что пользователь видит на экране. С помощью UI state приложение управляет тем, что пользователь увидит на экране.

Два этих понятия — как две стороны одной монеты: UI — это визуальное представление UI-состояния. Любые изменения UI-состояния немедленно отражаются в UI.

UI – результат привязки UI элементов на экране к UI-состоянию

UI – результат привязки UI элементов на экране к UI-состоянию

Чтобы выполнить требования новостного приложения, информацию, необходимую для полной отрисовки UI, можно инкапсулировать в класс данных NewsUiState, который описывают следующим образом:

data class NewsUiState(

    val isSignedIn: Boolean = false,

    val isPremium: Boolean = false,

    val newsItems: List<NewsItemUiState> = listOf(),

    val userMessages: List<Message> = listOf()

)

data class NewsItemUiState(

    val title: String,

    val body: String,

    val bookmarked: Boolean = false,

    ...

)

Неизменяемость

В предыдущем примере UI-состояние описано как неизменяемое. Основное преимущество такого подхода — неизменяемые объекты гарантируют целостность состояния приложения в любой момент времени. 

Благодаря этому UI может полностью сконцентрироваться на единственной задаче: считывать состояние и в соответствии с ним обновлять элементы UI. Из этого следует, что менять UI-состояние в UI напрямую нельзя — если только UI сам по себе не является единственным источником получаемых им данных. 

Если нарушить этот принцип, у одной и той же информации появится несколько source of truth (источников истины), что приведёт к противоречивости данных и багам, которые трудно обнаружить.

Скажем, если бы в флаг bookmarked в объекте NewsItemUiState из UI-состояния обновлялся в классе Activity, за статус статьи «сохранена» отвечали бы параллельно и этот флаг, и слой данных. Неизменяемые классы помогают успешно предотвратить возникновение таких антипаттернов.

Ключевой момент: только классы DataSource или сущности, распоряжающиеся данными, должны отвечать за обновление данных, к которым они открывают доступ.

Правила именования в этом гайде

Классы UI-состояния названы в соответствии с описываемой ими функциональностью на экране или части экрана. Правило выглядит следующим образом:

функциональность + UiState

К примеру, состояние, при котором на экране отображены новости, будет называться NewsUiState. Состояние, при котором статья отображается в списке статей, — NewsItemUiState.

Как управлять состоянием с помощью UDF

UI-состояние – это неизменяемое описание информации, необходимой для отрисовки UI. Но данные в приложениях подвержены изменениям, поэтому и состояние со временем может меняться. Причиной этому может стать взаимодействие с пользователем или другие события, которые меняют данные в приложении.

Лучше обрабатывать эти взаимодействия с помощью дополнительной сущности:

  • она будет описывать логику, применяемую к каждому событию,

  • и трансформировать данные, получаемые из источников, чтобы создать UI-состояние. 

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

Это может сказаться и на удобстве тестирования: код превратится в сплав тесно связанных элементов без чётко выраженных границ. По большому счёту UI только выигрывает от того, что нагрузка на него сокращается. Единственной ответственностью UI должно быть получение и отображение UI-состояния — за исключением случаев, когда UI-состояние элементарно.

В этом разделе рассматривается UDF — архитектурный шаблон, который помогает привести код в порядок, разделив ответственности.

State holder

State holder — классы, отвечающие за производство UI-состояния и содержащие необходимую для этого логику. State holder бывает всевозможных размеров в зависимости от масштаба соответствующих элементов UI, которыми он управляет. Так, его размер может варьироваться от одного виджета вроде нижней панели навигации до целого экрана или конечной точки навигации.

В последнем случае его реализация – это, как правило, экземпляр ViewModel. Однако, в зависимости от требований приложения, иногда можно обойтись обычным классом. Так, новостное приложение из примера использует в качестве state holder класс NewsViewModel: он производит UI-состояние для экрана, изображённого в начале статьи.

Ключевой момент: тип ViewModel — реализация, у которой есть доступ к слою данных. С помощью него рекомендуется управлять UI-состоянием в масштабе целого экрана. Помимо прочего, он автоматически переживает изменения конфигураций. Класс ViewModel определяет логику, которая применяется к событиям в приложении, и в результате производит обновлённое состояние.

Смоделировать взаимозависимость между UI и сущностью, которая производит его состояние, можно множеством способов. Так как под взаимодействием между UI и его классом ViewModel по большей части подразумевают ввод некоего события и вывод соответствующего состояния, их отношения можно изобразить следующим образом:

Схематичное изображение работы UDF в рамках архитектуры приложения

Схематичное изображение работы UDF в рамках архитектуры приложения

UDF — паттерн, в котором поток состояния направлен вниз, а поток событий – вверх. Вот что этот паттерн даёт архитектуре приложения:

  • ViewModel хранит состояние и открывает к нему доступ для UI. UI-состояние – это данные приложения, преобразованные ViewModel.

  • UI уведомляет ViewModel о пользовательских событиях.

  • ViewModel обрабатывает действия пользователя и обновляет состояние.

  • Обновлённое состояние возвращается обратно в UI, а тот его отрисовывает.

  • Все предыдущие пункты повторяются с каждым событием, меняющим состояние.

В случае с конечными точками навигации или экранами ViewModel получает данные из репозиториев или классов UseCase, а затем преобразует их в UI-состояния, применяя к ним эффекты событий, вызвавших изменение состояния. В упомянутом ранее примере есть список статей: у каждой указаны заголовок, описание, источник, имя автора, дата публикации и возможна пометка «добавлено в закладки». UI каждой статьи выглядит так:

UI статьи в приложении из примера

UI статьи в приложении из примера

Когда пользователь отправляет запрос, чтобы добавить статью в закладки, он создаёт событие, которое способно изменить состояние. Так как ViewModel производит состояния, его ответственность – описывать логику, необходимую для заполнения всех полей в UI-состоянии, и обрабатывать события, без которых UI не сможет отрисоваться полностью.

Цикл событий и данных в UDF

Цикл событий и данных в UDF

В следующих разделах — о событиях, которые ведут к изменению состояния, и способах их обработки с помощью UDF.

Виды логики

  • Бизнес-логика — то, как меняется состояние. Один из примеров — добавление новостной статьи в закладки: эта фича наделяет приложение ценностью. Бизнес-логику обычно помещают в доменный слой или слой данных, но точно не в слой UI.

  • Логика поведения UI или логика UI — то, как мы отображаем изменения состояния на экране. Например, с помощью Android Resources получаем текст, который нужно отобразить на экране; переходим на нужный экран, когда пользователь нажимает на кнопку; или показываем пользователю сообщение на экране с помощью Toast или Snackbar.

Логика UI, в особенности когда она затрагивает такие типы UI, как Context, должна находиться в UI, а не во ViewModel. Если UI приложения усложняется, и вам хочется делегировать логику UI другому классу, чтобы разделить ответственности и легче тестировать приложение, можно создать простой класс, который будет выполнять роль экземпляра state holder. Простые классы, созданные в UI, могут получать зависимости от Android SDK: их жизненный цикл ограничен жизненным циклом UI, в то время как объекты ViewModel живут дольше.

Подробнее о state holder и том, как он помогает построить UI, можно почитать в гайде «Jetpack Compose State».

Зачем использовать UDF

UDF моделирует цикл производства состояний, как показано на рисунке выше. Также он отделяет источник изменений состояния от места их трансформации и получения. Благодаря такому разделению UI может выполнять только те действия, которые следуют из его названия: отслеживать изменения состояния и сообщать о намерениях пользователя, передавая эти изменения во ViewModel, а в результате отображать информацию.

Другими словами, UDF позволяет добиться:

  • Согласованности данных. У UI есть только один источник правды.

  • Удобства тестирования. Источник состояния изолирован, а значит, его можно тестировать отдельно от UI.

  • Надёжности. Изменение состояния следует чётко заданному паттерну: изменения вызываются пользовательскими событиями и источниками данных, которые они запрашивают.

Как предоставлять доступ к UI-состоянию

После того, как вы описали UI-состояние и определили, как будете управлять его производством, следующий шаг – предоставить UI доступ к готовому состоянию. 

Так как вы управляете производством состояния с помощью UDF, рекомендуется сделать производимое состояние потоком — другими словами, в процессе работы программы будет произведено несколько версий этого состояния. В таком случае доступ к UI-состоянию следует предоставить с помощью observable-обёртки над данными, к примеру LiveData или StateFlow. Это нужно сделать, чтобы UI мог реагировать на все изменения, внесённые в состояние, и вам не приходилось вручную получать данные прямо из ViewModel. 

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

Views

class NewsViewModel(...) : ViewModel() {

val uiState: StateFlow = …

}

Compose

class NewsViewModel(...) : ViewModel() {
  
    val uiState: NewsUiState = …
  
}

Вводную информацию об использовании LiveData в качестве observable-обёртки над данными можно прочитать в этом кодлабе. Вводную информацию о flow в Kotlin — в статье «Flow в Kotlin на Android».

Важно: чтобы предоставить доступ к UI-состоянию в приложениях с Jetpack Compose, можно использовать его родные observable State API, например mutableStateOf или snapshotFlow. Все указанные в этом гайде типы observable-обёрток над данными, такие как StateFlow или LiveData, легко можно использовать в Compose с помощью соответствующих extension функций.

Если данные, доступ к которым открыт для UI, относительно просты, их чаще всего стоит обернуть в тип UI-состояния: он сообщает программе, как взаимосвязаны отправленный экземпляр state holder и соответствующий экран или элемент UI. Когда элемент UI станет сложнее, проще будет внести в описание UI-состояния дополнительную информацию, если она потребуется для отрисовки элемента UI.

Поток данных UiState зачастую создают, предоставляя из ViewModel доступ к приватному изменяемому потоку как к неизменяемому: например, доступ к MutableStateFlow<UiState> как к StateFlow<UiState>.

Views

class NewsViewModel(...) : ViewModel() {

    private val _uiState = MutableStateFlow(NewsUiState())

    val uiState: StateFlow<NewsUiState> = _uiState.asStateFlow()

    ...

}

Compose

class NewsViewModel(...) : ViewModel() {

    var uiState by mutableStateOf(NewsUiState())
        private set

    ...
}

Благодаря этому ViewModel сможет предоставлять доступ к методам, которые изменяют состояние изнутри, публикуя обновления, которые получит UI. Возьмём, к примеру, кейс, в котором нужно выполнить асинхронное действие. В этом случае можно запустить корутину с помощью viewModelScope, а по завершении обновить изменяемое состояние.

Views

class NewsViewModel(
    private val repository: NewsRepository,
    ...
) : ViewModel() {

    private val _uiState = MutableStateFlow(NewsUiState())
    val uiState: StateFlow<NewsUiState> = _uiState.asStateFlow()

    private var fetchJob: Job? = null

    fun fetchArticles(category: String) {
        fetchJob?.cancel()
        fetchJob = viewModelScope.launch {
            try {
                val newsItems = repository.newsItemsForCategory(category)
                _uiState.update {
                    it.copy(newsItems = newsItems)
                }
            } catch (ioe: IOException) {
                // Handle the error and notify the notify the UI when appropriate.
                _uiState.update {
                    val messages = getMessagesFromThrowable(ioe)
                    it.copy(userMessages = messages)
                 }
            }
        }
    }
}

Compose

class NewsViewModel(
    private val repository: NewsRepository,
    ...
) : ViewModel() {

   var uiState by mutableStateOf(NewsUiState())
        private set

    private var fetchJob: Job? = null

    fun fetchArticles(category: String) {
        fetchJob?.cancel()
        fetchJob = viewModelScope.launch {
            try {
                val newsItems = repository.newsItemsForCategory(category)
                uiState = uiState.copy(newsItems = newsItems)
            } catch (ioe: IOException) {
                // Handle the error and notify the notify the UI when appropriate.
                val messages = getMessagesFromThrowable(ioe)
                uiState = uiState.copy(userMessages = messages)
            }
        }
    }
}

В примере выше класс NewsViewModel пытается составить выборку статей определённой категории. Затем отражает результаты попытки — удачные или неудачные — в UI-состоянии, на которое UI реагирует соответствующим образом. Чтобы узнать больше о работе с ошибками, прочитайте раздел «Отображение ошибок на экране».

Важно: шаблон из предыдущего примера, где состояние изменяют посредством функций во ViewModel, — одна из наиболее популярных реализаций UDF.

Дополнительные рекомендации

Предоставляя доступ к UI-состоянию, следует учитывать:

  • Объект UI-состояния должен обрабатывать состояния, которые связаны друг с другом. В таком случае неконсистентность будет возникать реже, а код будет проще понять. Если открыть доступ к списку статей и количеству сохранённых статей в двух разных потоках данных, можно оказаться в ситуации, где одни данные обновились, а другие – нет. Если использовать один поток, оба элемента будут содержать актуальные данные.

    Более того, в некоторых случаях бизнес логика может потребовать слияния источников. К примеру, вам может потребоваться показывать кнопку «добавить в закладки» только если пользователь зарегистрировался и подписан на премиум услугу. В таком случае класс UI-состояния можно описать следующим образом:

data class NewsUiState(
    val isSignedIn: Boolean = false,
    val isPremium: Boolean = false,
    val newsItems: List<NewsItemUiState> = listOf()
)

val NewsUiState.canBookmarkNews: Boolean get() = isSignedIn && isPremium

В этом описании наличие или отсутствие кнопки «добавить в закладки» — это свойство, унаследованное от двух других свойств. Чем сложнее становится бизнес-логика приложения, тем удобнее иметь один единственный класс UiState, где в вашем распоряжении есть все свойства.

  • UI-состояния: один поток или несколько? Если вы выбираете, открыть доступ к UI-состоянию в одном потоке или в нескольких, основным ориентиром должен стать предыдущий пункт: связь между отправляемыми элементами.

    Основной плюс одного потока – удобство и консистентность данных: получатели состояния всегда принимают наиболее актуальную информацию. Однако бывают случаи, когда удобнее получать из ViewModel несколько потоков состояний:

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

    • Сравнение UiState. Чем больше в объекте UiState полей, тем вероятнее, что поток будет отправлять данные при обновлении одного из его полей. View обновляется в каждом случае: у него нет механизма сравнения, с помощью которого можно было бы понять, отличаются отправляемые друг за другом данные или нет. В такой ситуации для решения проблемы вам могут потребоваться Flow API или методы типа distinctUntilChanged() на LiveData.

Как принимать UI-состояния

Чтобы UI начал получать UiState из потока, используется терминальный оператор, соответствующий конкретному observable-типу данных в коде. Например, в случае с LiveData используется метод observe(), а в случае с flow в Kotlin – метод collect() или его вариации.

Когда запускаете получение observable-обёрток над данными в UI, убедитесь, что учли жизненный цикл UI. Это важно: UI не должен отслеживать UI-состояние, когда view пользователю не показывают. 

Подробнее тему можно изучить в посте «A safer way to collect flows from Android UIs». Когда используется LiveData, LifecycleOwner сам решает вопрос жизненных циклов. В случае с flow лучше использовать соответствующий coroutine scope и repeatOnLifecycle API:

Views

class NewsActivity : AppCompatActivity() {

    private val viewModel: NewsViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        ...

        lifecycleScope.launch {
            repeatOnLifecycle(Lifecycle.State.STARTED) {
                viewModel.uiState.collect {
                    // Update UI elements
                }
            }
        }
    }
}

Compose

@Composable
fun LatestNewsScreen(
    viewModel: NewsViewModel = viewModel()
) {
    // Show UI elements based on the viewModel.uiState
}

Важно: объекты StateFlow, использованные в этом примере, не прекращают работу, когда у них нет активных получателей данных. Но, работая с flow, вы можете и не знать, как они реализованы. Получение данных flow с учётом жизненного цикла позволяет вносить подобные изменения в потоки ViewModel позднее — без необходимости дорабатывать код получателя данных.

Как отображать прогресс выполнения операций

Проще всего отобразить состояние загрузки в классе UiState с помощью поля boolean:

data class NewsUiState(

    val isFetchingArticles: Boolean = false,

    ...

)

Значение этого флага указывает на наличие или отсутствие прогресс-бара в UI.

Views

class NewsActivity : AppCompatActivity() {

    private val viewModel: NewsViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        ...

        lifecycleScope.launch {
            repeatOnLifecycle(Lifecycle.State.STARTED) {
                // Bind the visibility of the progressBar to the state
                // of isFetchingArticles.
                viewModel.uiState
                    .map { it.isFetchingArticles }
                    .distinctUntilChanged()
                    .collect { progressBar.isVisible = it }
            }
        }
    }
}

Compose

@Composable
fun LatestNewsScreen(
    modifier: Modifier = Modifier,
    viewModel: NewsViewModel = viewModel()
) {
    Box(modifier.fillMaxSize()) {

        if (viewModel.uiState.isFetchingArticles) {
            CircularProgressIndicator(Modifier.align(Alignment.Center))
        }

        // Add other UI elements. For example, the list.
    }
}

Отображение ошибок на экране

Показывать ошибки в UI – то же самое, что показывать прогресс выполнения операции: оба случая легко представить с помощью Boolean-значения, которое обозначает наличие или отсутствие чего-либо. 

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

Возьмём пример из предыдущего раздела, где в процессе поиска статей отображался прогресс-бар. Если в результате операции возникнет ошибка, вы, возможно, захотите показать пользователю сообщение «что пошло не так».

data class Message(val id: Long, val message: String)

data class NewsUiState(

    val userMessages: List<Message> = listOf(),

    ...

)

В таком случае сообщения об ошибке можно представить пользователю в виде таких элементов UI, как Snackbar. Так как этот пункт связан с производством и получением событий UI, вы можете почитать главу события UI, чтобы изучить тему подробнее.

Потоки и параллелизм

Любая операция, которую мы выполняем в ViewModel, должна быть main-safe: вызывать её из главного потока должно быть безопасно. За переключение работы в другой поток отвечают слои данных и предметной области.

Если ViewModel выполняет продолжительные операции, она также отвечает за перемещение этой логики в фоновый поток. Корутины в Kotlin – отличный способ управления параллельными операциями, а Jetpack Architecture Components предоставляют встроенную поддержку корутин. Вы можете подробнее узнать о том, как использовать корутины в приложениях на Android, если прочитаете статью «Корутины Kotlin в Android».

Навигация

Изменения в навигации приложения зачастую обусловлены получением событий или подобных им сущностей. К примеру, после того, как класс SignInViewModel выполняет регистрацию, поле isSignedIn в UiState может иметь значение true. Такие триггеры следует принимать так же, как и описанные в предыдущем разделе Как принимать UI-состояния. Единственное исключение состоит в том, что получатель состояния следует реализовать, полагаясь на Navigation component.

Пагинация

Paging library передает на UI-класс PagingData. Так как PagingData представляет и содержит элементы, которые могут меняться с течением времени (то есть не относятся к неизменяемому типу), его не следует представлять в неизменяемом UI-состоянии. Логичнее будет предоставить к нему доступ из ViewModel в отдельном потоке. Конкретные примеры можно посмотреть в кодлабе Android Paging.

Анимации

Чтобы анимации переходов были качественными и плавными, иногда приходится подождать, пока загрузятся данные со следующего экрана, прежде чем стартовать анимацию. В Android view фреймворке есть методы, с помощью которых можно отсрочить переход между фрагментами с postponeEnterTransition() API и startPostponedEnterTransition() API. Эти API помогают убедиться, что элементы UI на следующем экране (как правило, изображения, которые загружаются из сети) готовы к отрисовке, прежде чем UI анимирует переход на этот экран. Подробную информацию и способы применения вы найдёте в Android Motion sample.

Читайте далее

Обзор архитектуры

События UI

Доменный слой

Слой данных


Больше полезного про Android — в нашем телеграм-канале Surf Android Team. Здесь мы публикуем кейсы, лучшие практики, новости и вакансии Surf, а также проводим прямые эфиры. Присоединяйтесь!

В этом курсе вы познакомитесь с основами дизайна пользовательского интерфейса Android. Вы поймете пользовательский ввод, представления и макеты, а также адаптеры и фрагменты. Проверьте это здесь !

1. Введение

В этой последней статье о пользовательском интерфейсе Android мы создадим приложение для Android, которое использует почти все концепции, о которых мы говорили в предыдущих статьях. Мы говорили о наиболее важных аспектах, которые необходимо учитывать при разработке приложения для Android. Мы увидели, как создать структуру пользовательского интерфейса с помощью менеджеров макетов и как мы можем размещать виджеты; мы описали некоторые лучшие практики, которые мы должны использовать при разработке приложения. Итак, приложение, которое мы создадим, будет основано на темах, которые мы уже обсуждали ранее, поэтому взгляните на них еще раз, чтобы освежить вашу память.

В качестве примера мы создадим приложение To Do app : это простое приложение, в которое мы можем добавлять элементы задач и управлять ими. Мы расскажем, как создать структуру макета пользовательского интерфейса, как добавить виджеты, чтобы мы могли показывать текстовые сообщения пользователю, и как принимать пользовательский ввод. Важным аспектом, который мы рассмотрим, является создание приложения, которое можно использовать на нескольких устройствах с разным размером экрана и разрешением.

2. Структура приложения

Прежде чем углубляться в детали кода, первое, что мы должны учитывать при создании приложения, — это сделать несколько набросков, которые помогут нам понять навигацию приложения и взаимодействие с пользователем. Мы можем использовать несколько инструментов, некоторые из них бесплатны. Кроме того, эти эскизы помогают нам понять, как будет выглядеть наше приложение, и мы могли бы показать их нашим клиентам, чтобы они могли понять, соответствует ли приложение, которое мы хотим построить, их потребностям.

Возвращаясь к нашему приложению To do, мы можем представить, что у нас есть следующие требования:

  • Там должен быть список предметов (для выполнения предметов).
  • Пользователь может добавить элемент к существующим.
  • Предметы должны иметь приоритетный цвет.
  • Приложение должно работать на смартфоне и планшете.

Конечно, в реальном приложении требования будут намного сложнее, но это всего лишь ступенька. Мы можем представить простую навигацию, подобную этой:

фигура 1

фигура 1

фигура 2

фигура 2

Это очень простая навигация: при запуске приложение отображает текущий список элементов, а когда пользователь нажимает «Добавить элемент» на панели действий. приложение покажет экран добавления элемента. Для простоты и сосредоточенности на аспектах пользовательского интерфейса мы можем предположить, что приложение не будет сохранять элементы. Читателю может быть интересно расширить приложение, чтобы оно сохраняло элементы.

Теперь, когда мы примерно знаем, какой будет навигация и как будет выглядеть пользовательский интерфейс приложения, мы можем приступить к созданию нашего приложения с помощью нашей IDE. В этом случае мы будем использовать Eclipse + ADT. Мы создаем новый проект Android, который мы можем назвать Todo . Мы не будем рассказывать, как создать проект Android с использованием Eclipse, поэтому мы предполагаем, что вы уже знакомы с этой IDE. Посмотрите наш пример «Android Hello World», если вы не знакомы с процессом.

2.1. Список предметов с ListView и объектной моделью

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

1

2

3

4

5

6

7

8

public class Item implements Serializable {

    private String name;   

    private String descr;

    private Date date;

    private String note;

    private TagEnum tag;

}

Это будет основной класс, который мы будем обрабатывать в нашем приложении. Глядя на проект Android, который мы только что создали, мы можем заметить, что под каталогом макетов есть макет по умолчанию, называемый activity_main.xml . Это макет по умолчанию, созданный инструментом.

К настоящему времени мы можем предположить, что у нас есть только список элементов в этом макете: этот макет будет использоваться только для смартфона, и мы рассмотрим позже, когда приложение будет работать на планшете. Расположение элемента списка очень простое, оно просто создается стандартным виджетом ListView :

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:paddingBottom="@dimen/activity_vertical_margin"

    android:paddingLeft="@dimen/activity_horizontal_margin"

    android:paddingRight="@dimen/activity_horizontal_margin"

    android:paddingTop="@dimen/activity_vertical_margin"

    tools:context=".MainActivity" >

    <ListView

        android:id="@+id/listItmes"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content" />

</RelativeLayout>

Если вы заметили, мы дали указание Android использовать только пространство, необходимое для хранения элементов в списке. Мы знаем, что для использования ListView мы должны реализовать адаптер. Мы могли бы использовать стандартный адаптер, предоставляемый Android, но в этом случае этих стандартных адаптеров недостаточно, мы хотим реализовать собственный адаптер, потому что мы хотели бы показать некоторую информацию для каждой строки в списке. Нам бы хотелось, чтобы строка в списке выглядела так:

Рисунок 3

Рисунок 3

Как вы можете заметить, каждая строка имеет изображение слева, которое представляет приоритет задачи и некоторую информацию. В настоящее время мы не рассматриваем применение какого-либо стиля к нашим строкам. Чтобы иметь такую ​​строку в нашем ListView , мы должны создать макет строки, который мы будем использовать в нашем настраиваемом адаптере. Таким образом, мы можем создать новый файл с именем item_layout.xml в директории layout . Этот файл выглядит так:

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

    android:layout_width="match_parent"

    android:layout_height="match_parent" >

    <ImageView

        android:id="@+id/tagView"

        android:layout_width="30dp"

        android:layout_height="20dp"

        android:background="@color/red" />

    <TextView

        android:id="@+id/nameView"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_alignParentTop="true"

        android:layout_toRightOf="@id/tagView" />

    <TextView

        android:id="@+id/descrView"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_below="@id/nameView"

        android:layout_toRightOf="@id/tagView" />

    <TextView

        android:id="@+id/dateView"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_alignParentBottom="true"

        android:layout_alignParentRight="true" />

</RelativeLayout>

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

1

android:layout_toRightOf="@id/tagView"

Более того, мы можем размещать представления относительно родителя, например, мы хотим, чтобы информация о дате была размещена справа от строки и внизу:

1

2

android:layout_alignParentRight="true"

android:layout_alignParentBottom="true"

Теперь, когда у нас есть макет, мы должны построить адаптер. Мы расширим ArrayAdapter и переопределим некоторые методы, чтобы мы могли обрабатывать данные нашей модели и новый макет. Мы называем этот адаптер ToDoItemAdaper , поэтому мы имеем:

1

2

3

4

5

6

7

8

9

public class ToDoItemAdapter extends ArrayAdapter<Item> {

    private Context ctx;

    private List<Item> itemList;

    public ToDoItemAdapter(Context context, List<Item> itemList) {

        super(context, R.layout.item_layout);

        this.ctx = context;

        this.itemList = itemList;

    }

}

Конструктор получает Context и itemList качестве параметров, последний параметр содержит список элементов todo. Вы можете заметить, что когда мы вызываем супер метод, мы R.layout.item_layout пользовательский макет с именем R.layout.item_layout . Теперь нам нужно переопределить один из наиболее важных методов, называемый getView , который используется для создания View и рендеринга макета строки:

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

@Override

public View getView(int position, View convertView, ViewGroup parent) {

    View v = convertView;

    ItemHolder h = null;

    if (v == null) {

        LayoutInflater inf = (LayoutInflater) ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        v = inf.inflate(R.layout.item_layout, parent, false);

        ImageView iv = (ImageView) v.findViewById(R.id.tagView);

        TextView nameTv = (TextView) v.findViewById(R.id.nameView);

        TextView descrView = (TextView) v.findViewById(R.id.descrView);

        TextView dateView = (TextView) v.findViewById(R.id.dateView);

        h = new ItemHolder();

        h.tagView = iv;

        h.nameView = nameTv;

        h.descrView = descrView;

        h.dateView = dateView;

        v.setTag(h);

    }

    else       

       h = (ItemHolder) v.getTag();

    h.nameView.setText(itemList.get(position).getName());      

    h.descrView.setText(itemList.get(position).getDescr());

    h.tagView.setBackgroundResource(itemList.get(position).getTag().getTagColor());

    h.dateView.setText(sdf.format(itemList.get(position).getDate()));

    return v;

}

В этом методе мы проверяем в начале, является ли представление, которое мы получаем как параметр, нулевым. В этом случае мы должны надуть наш макет. Если вы заметили, мы использовали шаблон ViewHolder , чтобы сделать прокрутку ListView более плавной. Мы создали небольшой внутренний класс ItemHolder который содержит ссылки на View внутри нашего пользовательского макета:

1

2

3

4

5

6

7

static class ItemHolder {

    ImageView tagView;

    TextView nameView;

    TextView descrView;

    TextView dateView;     

}

Одна вещь, которую вы должны заметить, это то, как мы обрабатывали цвет фона ImageView . Мы использовали setBackgroundResource для установки imageview изображения. Этот метод принимает int, представляющий идентификатор ресурса, который мы хотим использовать в качестве фона:

1

h.tagView.setBackgroundResource(itemList.get(position).getTag().getTagColor());

Глядя на наш класс модели, мы можем заметить, что метод getTag() возвращает экземпляр класса TagEnum . Это перечисление, определенное следующим образом:

01

02

03

04

05

06

07

08

09

10

11

12

13

public enum TagEnum {

    BLACK(R.color.black,"Black"), RED(R.color.red, "Red"),

    GREEN(R.color.green, "Green"), BLUE(R.color.blue, "Blue"),YELLOW(R.color.yellow,"Yellow");

    private int code;

    private String name;

    private TagEnum(int code, String name) {

        this.code = code;

        this.name = name;

    }

    public int getTagColor() {

        return this.code;

    }

}

В перечислении мы определяем различные цвета, которые мы хотим поддерживать, и в качестве первого параметра мы передаем идентификатор ресурса. Если вы помните, в предыдущей статье мы говорили о том, как определить цвет ресурса в формате XML. Мы уже знаем, что нам нужно создать XML-файл в res/values который мы можем назвать colors.xml :

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

<resources>

    <color name="red" >#FF0000

    </color>

    <color name="green" >#00FF00

    </color>

    <color name="blue" >#0000FF

    </color>

    <color name="black" >#000000

    </color>

    <color name="yellow" >#FFAA00

    </color>

</resources>

В определении цвета перечисления мы ссылались на этот цвет, используя R.color.color_name , поэтому, когда мы используем метод getTagColor в пользовательском адаптере getView , мы получаем идентификатор ресурса, который будет использоваться фоном изображения. Важно понимать, что мы не жестко кодировали цвета в конструкторе: например, мы могли напрямую использовать шестнадцатеричный код цвета, например, # FF0000 для красного и так далее.

Даже если результат будет таким же, не рекомендуется использовать жестко закодированные значения в исходном коде. Например, если мы хотим изменить красный цвет на другой, нам нужно будет найти шестнадцатеричный цвет в исходном коде и изменить его, но если бы мы использовали ресурсы для определения цветов, мы бы обратились непосредственно к файлу, содержащему определения цвета и изменить цвет, который нам нравится.

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

2.2. Поддержка нескольких устройств и особенности компоновки

Помните, что одним из наших требований является создание приложения, которое поддерживает как смартфоны, так и планшеты. Думая о размерах экрана планшета, мы понимаем, что экран слишком большой, чтобы вместить только список элементов, поэтому мы могли бы рассмотреть возможность разделения экрана на две области: одну, в которой содержится список, и другую, которую мы можем использовать для отображения деталей элемента или даже показать пользовательский интерфейс, чтобы добавить новый элемент. Это верно, если мы используем планшеты, но если у нас смартфон, размеры экрана недостаточно велики, чтобы разделить их на две части.

В то же время мы не хотим разрабатывать две разные ветви кода: одну для смартфона и одну для планшета. Мы переписали бы тот же код, изменив только некоторые детали и измерения. Android помогает нам решить эту проблему: мы говорили о Fragment в предыдущей статье . Таким образом, мы могли бы создать фрагмент, который обрабатывает пользовательский интерфейс, чтобы добавить новый элемент в список. Фрагмент инкапсулирует набор компонентов и поведения действий, чтобы мы могли повторно использовать этот фрагмент кода в различных действиях. На рисунках ниже показана ситуация, с которой мы должны справиться:

Рисунок 4

Рисунок 4

Рисунок 5

Рисунок 5

Когда приложение запускается на смартфоне, нам приходится обрабатывать два действия: одно для элемента списка, а другое — для ввода данных пользователем, в то время как на планшете у нас может быть только одно действие.

Мы можем предположить, что размер экрана составляет не менее 600 dp, поэтому мы хотим разделить экран на другие области и определить новый макет в res/layout-sw600dp :

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:paddingBottom="@dimen/activity_vertical_margin"

    android:paddingLeft="@dimen/activity_horizontal_margin"

    android:paddingRight="@dimen/activity_horizontal_margin"

    android:paddingTop="@dimen/activity_vertical_margin"

    tools:context=".MainActivity" >

    <ListView

        android:id="@+id/listItmes"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_weight="1" />

    <FrameLayout

        android:id="@+id/frm1"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_weight="1" />

</LinearLayout>

где FrameLayout будет «заполняться» динамически в зависимости от потока навигации.

Конечно, мы можем настроить макет более подробно, в соответствии с различными размерами экрана. В этом случае мы можем просто создать разные макеты в разных каталогах под res.

2,3. Добавить элемент макета пользовательского интерфейса

Если мы запустим приложение, то получим пустой список без элементов. Мы должны создать новый пользовательский интерфейс. Поэтому, учитывая соображения, которые мы делали ранее, мы создаем Fragment который обрабатывает функциональность добавления элемента, называя его NewItemFragment . Фрагмент имеет сложный жизненный цикл, но для этого мы можем переопределить только метод onCreateView . Этот метод отвечает за создание пользовательского интерфейса. Как всегда, мы должны сначала создать макет. В нашей IDE в res/layout мы создаем еще один XML-файл, который мы называем add_item_layout.xml :

001

002

003

004

005

006

007

008

009

010

011

012

013

014

015

016

017

018

019

020

021

022

023

024

025

026

027

028

029

030

031

032

033

034

035

036

037

038

039

040

041

042

043

044

045

046

047

048

049

050

051

052

053

054

055

056

057

058

059

060

061

062

063

064

065

066

067

068

069

070

071

072

073

074

075

076

077

078

079

080

081

082

083

084

085

086

087

088

089

090

091

092

093

094

095

096

097

098

099

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

    android:layout_width="match_parent"

    android:layout_height="match_parent" >

    <TextView

        android:id="@+id/txtTitle"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_centerHorizontal="true"

        android:text="@string/addItem" />

    <TextView

        android:id="@+id/itemName"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_below="@id/txtTitle"

        android:layout_marginStart="10dp"

        android:text="@string/addItemName" />

    <EditText

        android:id="@+id/edtName"

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:layout_alignParentLeft="true"

        android:layout_below="@id/itemName"

        android:hint="@string/addItemNameHint" />

    <TextView

        android:id="@+id/itemDescr"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_alignParentLeft="true"

        android:layout_below="@id/edtName"

        android:layout_marginTop="10dp"

        android:text="@string/addItemDescr" />

    <EditText

        android:id="@+id/edtDescr"

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:layout_alignParentLeft="true"

        android:layout_below="@id/itemDescr"

        android:hint="@string/addItemDescrHint" />

    <TextView

        android:id="@+id/itemNote"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_alignParentLeft="true"

        android:layout_below="@id/edtDescr"

        android:layout_marginTop="10dp"

        android:text="@string/addItemNote" />

    <EditText

        android:id="@+id/edtNote"

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:layout_alignParentLeft="true"

        android:layout_below="@id/itemNote"

        android:hint="@string/addItemNoteHint" />

    <TextView

        android:id="@+id/itemDate"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_alignParentLeft="true"

        android:layout_below="@id/edtNote"

        android:layout_marginTop="10dp"

        android:text="@string/addItemDate" />

    <TextView

        android:id="@+id/inDate"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_alignParentLeft="true"

        android:layout_below="@id/itemDate"

        android:layout_marginTop="10dp" />

    <TextView

        android:id="@+id/itemTime"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_alignParentLeft="true"

        android:layout_below="@id/inDate"

        android:layout_marginTop="10dp"

        android:text="@string/addItemTime" />

    <TextView

        android:id="@+id/inTime"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_alignParentLeft="true"

        android:layout_below="@id/itemTime"

        android:layout_marginTop="10dp" />

    <TextView

        android:id="@+id/itemTag"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_alignParentLeft="true"

        android:layout_below="@id/inTime"

        android:layout_marginTop="10dp"

        android:text="@string/addItemTag" />

    <Spinner

        android:id="@+id/tagSpinner"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_alignParentLeft="true"

        android:layout_below="@id/itemTag" />

    <Button

        android:id="@+id/addBtn"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_alignParentBottom="true"

        android:layout_centerHorizontal="true"

        android:text="@string/addButton" />

</RelativeLayout>

Это очень простой макет, созданный TextView и EditText : первый используется для отображения текстовых сообщений в пользовательском интерфейсе, а другой — для приема пользовательских данных. В этом макете важны два компонента: Spinner и Spinner Date/Time picker .

Спиннер — это компонент пользовательского интерфейса, который показывает только один элемент за раз и позволяет пользователю выбрать один элемент среди них. Мы используем этот компонент, чтобы показать различные цвета тегов / приоритеты. Это идеально подходит для нашей цели, на самом деле мы хотим, чтобы пользователь выбирал один цвет из списка цветов.

2,4. Цвет метки / приоритетный спиннер

Для правильной работы Spinner необходим адаптер массива. Android предоставляет список адаптеров, которые мы можем использовать, но мы хотим настроить их, потому что мы хотим показать изображение с цветом. Затем мы должны создать пользовательский адаптер так же, как мы делали для ListView . Сначала мы создаем макет строки с именем spinner_tag_layout.xml :

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

    android:layout_width="match_parent"

    android:layout_height="match_parent" >

    <ImageView

        android:id="@+id/tagSpinnerImage"

        android:layout_width="30dp"

        android:layout_height="20dp" />

    <TextView

        android:id="@+id/tagNameSpinner"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_toRightOf="@id/tagSpinnerImage" />

</RelativeLayout>

и наконец мы создаем наш адаптер:

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

public class TagSpinnerAdapter extends ArrayAdapter<TagEnum> {

    private Context ctx;

    private List<TagEnum> tagList;

    public TagSpinnerAdapter(Context ctx, List<TagEnum> tagList) {

        super(ctx, R.layout.spinner_tag_layout);

        this.ctx = ctx;

        this.tagList = tagList;

    }

    @Override

    public View getDropDownView(int position, View convertView, ViewGroup parent) {

        return _getView(position, convertView, parent);

    }

    @Override

    public View getView(int position, View convertView, ViewGroup parent) {

        return _getView(position, convertView, parent);

    }

    private View _getView(int position, View convertView, ViewGroup parent) {

        View v = convertView;

        if (v == null) {

            LayoutInflater inf = (LayoutInflater) ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

            v = inf.inflate(R.layout.spinner_tag_layout, parent, false);

        }

        ImageView iv = (ImageView) v.findViewById(R.id.tagSpinnerImage);

        TextView tv = (TextView) v.findViewById(R.id.tagNameSpinner);

        TagEnum t = tagList.get(position);

        iv.setBackgroundResource(t.getTagColor());

        tv.setText(t.getName());

        return v;

    }

}

Анализируя приведенный выше код, мы замечаем, что этот адаптер обрабатывает объекты TagEnum и мы переопределяем два метода getView и getDropDownView . Мы обрабатываем эти методы одинаково. Как вы можете заметить, мы сделали почти то же самое, что уже сделали для ListView.

Во фрагменте, который содержит эти компоненты пользовательского интерфейса, мы должны найти ссылку на Spinner и установить пользовательский макет, который мы определили выше:

1

2

3

Spinner sp = (Spinner) v.findViewById(R.id.tagSpinner);

TagSpinnerAdapter tsa = new TagSpinnerAdapter(getActivity(), tagList);

sp.setAdapter(tsa);

Когда пользователь выбирает один элемент в Spinner , мы должны найти способ узнать, какой элемент был выбран.

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

01

02

03

04

05

06

07

08

09

10

11

12

13

sp.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {

    @Override

    public void onItemSelected(AdapterView<?> adptView, View view,

        int pos, long id) {

        currentTag = (TagEnum) adptView.getItemAtPosition(pos);

    }

    @Override

    public void onNothingSelected(AdapterView<?> arg0) {

        }

    });

и мы храним результат в атрибуте класса.

2.5. Выбор даты и времени

Когда мы добавляем новый элемент todo в список, мы хотим, чтобы пользователь выбирал дату и время. Android предоставляет два компонента, которые называются DatePickerDialog и TimePickerDialog . Как следует из названия, это два диалоговых окна, которые можно открыть, чтобы выбрать дату и время.

Мы используем фрагменты, поэтому нам нужно создать два внутренних класса, которые представляют пользователю указатели даты и времени. В этом случае мы расширяем для обоих сборщиков класс DialogFragment и переопределяем метод onCreateDialog . В этом методе мы просто инициализируем средство выбора Date и возвращаем его как результат:

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

public static class DatePickerFragment extends DialogFragment implements DatePickerDialog.OnDateSetListener {

    @Override

        public Dialog onCreateDialog(Bundle savedInstanceState) {

            final Calendar c = Calendar.getInstance();

            c.setTime(selDate);

            int year = c.get(Calendar.YEAR);

            int month = c.get(Calendar.MONTH);

            int day = c.get(Calendar.DAY_OF_MONTH);

            return new DatePickerDialog(getActivity(), this, year, month, day);

        }

    @Override

    public void onDateSet(DatePicker view, int year, int monthOfYear,

                int dayOfMonth) {

        Calendar c = Calendar.getInstance();

        c.set(year, monthOfYear, dayOfMonth, 9, 0);

        selDate = c.getTime();

        tvDate.setText(sdfDate.format(selDate));

    }

}

Из приведенного выше кода вы можете заметить, что мы просто устанавливаем текущую дату в DatePickerDialog в onCreateDialog . Мы реализуем DatePickerDialog.OnDateSetListener чтобы получать уведомления, когда пользователь выбирает дату. В методе обратного вызова этого интерфейса мы просто сохраняем дату, выбранную пользователем.

Таким же образом мы обрабатываем TimePickerFragment , но в этом случае мы расширяем TimePickerDialog :

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

public static class TimePickerFragment extends DialogFragment implements TimePickerDialog.OnTimeSetListener {

    @Override

     public Dialog onCreateDialog(Bundle savedInstanceState) {

            final Calendar c = Calendar.getInstance();

            c.setTime(selDate);

            int hour = c.get(Calendar.HOUR_OF_DAY);

            int minute = c.get(Calendar.MINUTE);

         return new TimePickerDialog(getActivity(), this, hour, minute,

                        DateFormat.is24HourFormat(getActivity()));

            }

          @Override

          public void onTimeSet(TimePicker view, int hourOfDay, int minute) {

        Calendar c = Calendar.getInstance();

        c.setTime(selDate);

        c.set(Calendar.HOUR_OF_DAY, hourOfDay);

        c.set(Calendar.MINUTE, minute);

        selDate = c.getTime();

        tvTime.setText(sdfTime.format(selDate));

    }

}

Это два диалога, которые не отображаются сами по себе, но мы должны проверить, нажимает ли пользователь на текстовое представление даты / времени, чтобы открыть эти диалоги, поэтому мы имеем:

1

2

tvDate = (TextView) v.findViewById(R.id.inDate);

tvTime = (TextView) v.findViewById(R.id.inTime);

чтобы получить ссылку на TextView а затем мы просто реализуем слушатель:

1

2

3

4

5

6

7

tvDate.setOnClickListener(new View.OnClickListener() {

    @Override

    public void onClick(View v) {

        DatePickerFragment dpf = new DatePickerFragment();

        dpf.show(getFragmentManager(), "datepicker");

    }

});

В результате мы имеем:

Рисунок 6

Рисунок 6

Последняя часть в разработке этого фрагмента посвящена обработке события, когда пользователь нажимает кнопку добавления. Когда это событие происходит, фрагмент должен создать экземпляр класса Item, содержащий данные, вставленные пользователем, и отправить их обратно в операцию, которая содержит фрагмент. Лучшая практика предлагает использовать интерфейс и методы обратного вызова.

Мы можем определить этот интерфейс в классе фрагмента:

1

2

3

public interface AddItemListener {

    public void onAddItem(Item item);

}

Это очень простой интерфейс, созданный только одним методом. Теперь у нас есть:

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

Button addBtn = (Button) v.findViewById(R.id.addBtn);

addBtn.setOnClickListener(new View.OnClickListener() {

    @Override

    public void onClick(View v) {

        Item i = new Item();

        i.setName(edtName.getText().toString());

        i.setDescr(edtDescr.getText().toString());

        i.setNote(edtNote.getText().toString());

        i.setTag(currentTag);

        i.setDate(selDate);

        ( (AddItemListener) getActivity()).onAddItem(i);

    }

});

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

Возвращаясь к заметке, касающейся смартфонов и планшетов и вспоминая показанную выше картинку, мы знаем, что если приложение работает на смартфоне, нам нужно использовать два действия, поэтому мы создаем еще одно, называемое NewItemActivity которое будет содержать фрагмент, описанный выше. Это действие очень просто, потому что оно действует как контейнер фрагментов.

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

public class NewItemActivity extends Activity implements NewItemFragment.AddItemListener{

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        NewItemFragment nif = new NewItemFragment();

        getFragmentManager().beginTransaction().add(android.R.id.content, nif).commit();

    }

    @Override

    public void onAddItem(Item item) {

        Log.d("TODO", "onAddItem");

        Intent i = new Intent();

        i.putExtra("item", item);

        setResult(RESULT_OK,i);

        finish();

    }

}

В методе onCreate мы создаем новый экземпляр нашего класса фрагмента и, используя FragmentManager показываем фрагмент на экране.

Обратите внимание, что в этом действии реализован интерфейс, определенный во фрагменте, потому что он должен быть уведомлен, когда пользователь хочет добавить новый элемент, поэтому он реализует метод onAddItem . Мы расскажем о функциональности этого метода позже.

2.6. Основное занятие

Основное действие — это сердце приложения, это действие, которое вызывается при запуске. Он устанавливает начальный макет и показывает список элементов, который мы ранее описали:

1

2

3

itemListView = (ListView) findViewById(R.id.listItmes);

adpt = new ToDoItemAdapter(this, itemList);

itemListView.setAdapter(adpt);

Теперь мы должны проверить, работает ли наше приложение на смартфоне или планшете, чтобы мы могли изменить поведение активности. Мы можем сделать это, проверив, есть FrameLayout компонент FrameLayout в определении макета:

1

2

if (findViewById(R.id.frm1) != null)

   isTablet = true;

2,7. Панель действий

В этом упражнении мы добавляем панель действий (известный шаблон Android) с действием: добавить новый элемент. Чтобы определить его, мы создаем (если не существует) файл XML в res/menu :

1

2

3

4

5

6

7

8

9

    <item

        android:id="@+id/action_add"

        android:icon="@android:drawable/ic_menu_add"

        android:orderInCategory="0"

        android:showAsAction="always"/>

</menu>

В результате получаем:

Рисунок 7

Рисунок 7

Когда пользователь нажимает на знак плюс, мы должны показать пользовательский интерфейс для добавления нового элемента. Первое, что мы должны обработать, это событие, когда пользователь нажимает на значок «плюс», поэтому мы должны переопределить метод в классе активности:

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

@Override

public boolean onOptionsItemSelected(MenuItem item) {

    int menuId = item.getItemId();

    switch (menuId) {

        case R.id.action_add: {

            if (!isTablet) {

                Intent i = new Intent(this, NewItemActivity.class);

                startActivityForResult(i, ADD_ITEM);

                break;

            }

            else {

                Log.d("TODO", "Tablet");

                FragmentTransaction ft = getFragmentManager().beginTransaction();

                NewItemFragment nif = new NewItemFragment();

                ft.replace(R.id.frm1, nif);

                ft.commit();

            }

        }

    }

}

Этот метод очень важен, потому что мы определяем, как должна вести себя наша деятельность. Если кнопка, нажимаемая пользователем, является нашей кнопкой добавления, мы сначала проверяем, работает ли наше приложение на смартфоне. В этом случае мы знаем, что должны начать другое действие, и мы начинаем его, ожидая результата.

Если мы запускаем действие, ожидая его результата в вызываемом NewItemActivity мы должны вернуть результат, и мы делаем это в NewItemActivity следующим образом:

1

2

3

4

5

6

7

8

9

@Override

public void onAddItem(Item item) {

    Log.d("TODO", "onAddItem");

    Intent i = new Intent();

    i.putExtra("item", item);

    setResult(RESULT_OK,i);

    finish();

}

В этом методе мы создаем Intent, который содержит результат, и передаем его обратно в вызывающее действие ( MainActivity ), и мы завершаем действие. В MainActivity мы должны быть готовы обработать результат:

01

02

03

04

05

06

07

08

09

10

11

protected void onActivityResult(int requestCode, int resultCode, Intent data) {

    Log.d("TODO", "OnResult");

    if (requestCode == ADD_ITEM) {

        if (resultCode == RESULT_OK) {

            Log.d("TODO", "OK");

            Item i = (Item) data.getExtras().getSerializable("item");

            itemList.add(i);

            adpt.notifyDataSetChanged();

        }

    }

}

В этом упражнении мы извлекаем объект предмета, сохраненный в Intent которое мы получаем в результате, и добавляем его в список предметов. Когда мы закончим, мы вызываем метод notifyDataSetChange для обновления ListView .

Если наше приложение работает на планшете, мы просто «заполняем» NewItemFragment описанным выше NewItemFragment . В этом случае мы запускаем транзакцию и заменяем FrameLayout фрагментом, а в конце мы FrameLayout транзакцию. В этом случае нам не нужно запускать другое действие, потому что мы используем FrameLayout чтобы показать фрагмент, который обрабатывает пользовательский интерфейс для добавления нового элемента. Итак, мы имеем:

Рисунок 8

Рисунок 8

В этом случае мы должны просто реализовать интерфейс, указанный фрагментом, как мы делали раньше:

1

2

3

4

5

6

7

@Override

public void onAddItem(Item item) {

    itemList.add(item);

    adpt.notifyDataSetChanged();

    NewItemFragment nif = (NewItemFragment) getFragmentManager().findFragmentById(R.id.frm1);

    getFragmentManager().beginTransaction().remove(nif).commit();

}

Обратите внимание, что в последней части мы удалили фрагмент в конце.

3. Стилизация приложения

К настоящему времени мы не рассмотрели стиль приложения, но мы знаем, что можем применять стиль к каждому компоненту пользовательского интерфейса. Мы можем изменить все цвета и внешний вид пользовательского интерфейса, реализуя наш стиль и выпуская бренд приложения. Например, мы хотим применить стиль к строке listView, делая их немного более привлекательными. Мы создаем (если он еще не существует) файл с именем style.xml разделе res/values и здесь мы можем определить наш стиль, как мы обсуждали в предыдущей статье :

01

02

03

04

05

06

07

08

09

10

11

12

13

14

<style name="dateStyle">

        <item name="android:textAppearance">?android:textAppearanceSmall</item>

        <item name="android:textColor">@color/red</item>

    </style>

     <style name="descrStyle">

        <item name="android:textStyle">italic</item>

        <item name="android:textAppearance">?android:textAppearanceSmall</item>

    </style>

     <style name="nameStyle">

         <item name="android:textAppearance">?android:textAppearanceMedium</item>

         <item name="android:textStyle">bold</item>

     </style>

Мы определили три разных стиля и хотим применить их к нашей строке списка:

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

<TextView

    android:id="@+id/nameView"

    style="@style/nameStyle"

    android:layout_width="wrap_content"

    android:layout_height="wrap_content"

    android:layout_alignParentTop="true"

    android:layout_toRightOf="@id/tagView" />

<TextView

    android:id="@+id/descrView"

    style="@style/descrStyle"

    android:layout_width="wrap_content"

    android:layout_height="wrap_content"

    android:layout_below="@id/nameView"

    android:layout_toRightOf="@id/tagView" />

<TextView

    android:id="@+id/dateView"

    style="@style/dateStyle"

    android:layout_width="wrap_content"

    android:layout_height="wrap_content"

    android:layout_alignParentBottom="true"

    android:layout_alignParentRight="true" />

Запустив приложение с этим стилем мы имеем:

Рисунок 9

Рисунок 9

4. Вывод

В этом курсе по пользовательскому интерфейсу Android мы рассмотрели некоторые важные аспекты пользовательского интерфейса, концепции и лучшие практики, которым мы должны следовать при разработке приложения для Android. В этой последней статье мы увидели, как применить все эти знания для создания реального приложения, используя все темы, описанные в предыдущих статьях. Конечно, это простое приложение можно улучшить, и вы можете использовать его в качестве упражнения для добавления новых функций. Например, мы не рассмотрели, как изменить или удалить элементы в списке. В этом случае мы можем слушать, когда пользователь нажимает на элемент, и вы можете показать меню с несколькими опциями, или мы можем использовать панель действий, изменяя ее в соответствии с действиями пользователя. Например, мы могли бы создать представление списка с множественным выбором, и когда пользователь нажимает на значок «мусор» на панели действий, мы удаляем все выбранные элементы.

Есть несколько аспектов, которые мы можем улучшить в этом приложении, и это будет хорошим упражнением, если вы хотите углубиться в аспекты разработки Android.

5. Загрузите исходный код

Это был урок о том, как создать пользовательский интерфейс приложения Android с нуля. Вы можете скачать исходный код здесь: AndroidApp.zip

Building your Android UI Everything you need to know about Views

Every mobile app has some form of user interface (UI), and in Android user interfaces are created using Views.

If you’re just getting started with Android development, then it makes sense to familiarize yourself with Views as soon as possible, as they’re central to many “Hello World” apps and Android tutorials.

Even if you’ve been developing Android apps for a while, it’s easy to get into a rut! If you’re using the same Views over and over, then now’s the perfect time for a refresher on all the different Views that are included in the Android platform.

In this article, we’ll be taking a closer look at this essential building block of Android development, before exploring some of the most commonly-used Views that you can use in your Android apps.

What is a View, exactly?

View objects, sometimes referred to as “widgets” are the building blocks of all Android UIs.

Each View occupies a rectangular area of the screen and typically draws something that the user can see, such as text or an image. In addition to displaying content, some Views also provide interactive functionality, such as Buttons, EditTexts and Spinners. Whenever an event occurs Android dispatches this event to the appropriate View, which then handles the event and notifies any listeners.

You build your Android UI using a selection of Views

The easiest way to add a View to your Java or Kotlin project, is to define that View within an XML layout resource file. Android provides a simple XML syntax that corresponds to the different View subclasses, for example in the following snippet we’re using XML to instantiate a TextView:

Code

<TextView
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="Hello World!"
       app:layout_constraintBottom_toBottomOf="parent"
       app:layout_constraintLeft_toLeftOf="parent"
       app:layout_constraintRight_toRightOf="parent"
       app:layout_constraintTop_toTopOf="parent" />

The Android framework is responsible for measuring, laying out and drawing your Views, so you don’t have to explicitly call any methods to perform these actions.

To build a layout, simply keep adding View elements to your XML file, similar to how you create webpages in HTML – just try to keep nesting to a minimum, as it can negatively impact your application’s performance. User interfaces with “shallow” View hierarchies tend to be drawn faster, so if you’re going to deliver a high-performing app then you’ll need to avoid nesting wherever possible.

If you know all of a View’s properties at build time, then you can define this View entirely in XML. By keeping your UI code separate from your application code, you can provide alternate layouts that are optimized for different screen sizes, orientations and languages. This separation also makes your application code easier to read, test and modify, as it isn’t muddled up with UI code.

Since it’s the recommended approach, we’ll be defining Views in XML throughout this tutorial, although you can create Views programmatically where required.

If you need to edit a View’s properties at runtime, then’ll typically have to define some, or all of that View’s properties programmatically in Java or Kotlin. For example, in the following snippet we’re defining a TextView in Java:

Code

//Create a TextView programmatically//

        TextView tv = new TextView(getApplicationContext());

//Define the View’s layout parameters//

        LayoutParams lp = new LinearLayout.LayoutParams(

//Set the View’s width//

                  LayoutParams.WRAP_CONTENT,

//Set the View’s height//

                  LayoutParams.WRAP_CONTENT);

//Apply the layout parameters to the TextView//

        tv.setLayoutParams(lp);

//Set the text//

        tv.setText("Hello World!");

//Add the TextView to the parent ViewGroup//

        rl.addView(tv);
    }
}

Note that you may be able to declare your app’s default layout in XML, and then modify some of its properties at runtime.

Working with Views: Common XML attributes

When creating a View, you’ll need to define various View properties, using XML attributes. Some of these attributes will be unique to that particular View, but there are a number of XML attributes that you’ll encounter over and over again, regardless of the kind of View you’re working with.

Identifying your Views

Every View must have an integer ID that uniquely identifies that particular View. You define integer IDs in your layout files, for example:

Code

android:id="@+id/hello_world"

The + symbol signifies that this is a new name that must be created and added to your project’s R.java file.

When you need to work with a View, you can reference it using its View ID. Typically, you’ll reference a View by creating an instance of that View object in your Activity’s onCreate() method, for example:

Code

TextView myTextView = (TextView) findViewById(R.id.hello_world);

The ID integer technically doesn’t need to be unique throughout the entire tree, just within the part of the tree you’re searching. However, to avoid conflicts and confusion it’s recommended that you use completely unique View IDs, wherever possible.

Layout parameters: Width and height

XML attributes that start with “layout_” define a View’s layout parameters. Android supports a variety of layout parameters, but as a minimum you must define a width and height using the layout_width and layout_height attributes.

Android devices have screens of varying dimensions and pixel densities, so 10 pixels doesn’t translate to the same physical size across every device. If you define a View’s width and height using exact measurements, then this can result in user interfaces that only display and function correctly on devices with specific screens, so you should never use any exact measurements when creating your Views.

Instead, you can define a View’s width and height, using any of the following relative measurements:

  • wrap_content. This View should be just big enough to display its content, plus any padding.
  • match_parent. This View should be as big as its parent ViewGroup will allow.
  • dp. If you need more control over a View’s sizing, then you can provide a density-independent pixel measurement, for example android:layout_width=”50dp.” Note that one dp is roughly equal to one pixel on a “baseline” medium-density screen.
  • sp. If you want to size text using a density-independent pixel measurement, then you should use scalable pixels (sp), for example: android:textSize=”20sp.” Scalable pixels ensure that your app’s text respects the device’s selected text size, so your text will appear bigger on devices that are set to display Large text, and smaller on devices that are set to display Small text.

Give your content some breathing space!

You can use padding to insert some space between the edges of a View and the View’s content, which can be useful for giving your content some “breathing space” and preventing your UI from looking overly busy or cluttered.

The following screenshot shows an ImageView with 10dp of padding:

You can create breathing space by adding padding to your Views

An ImageView with 20dp of padding.

Android provides the following padding attributes:

  • android:padding. Adds extra space to all four edges. If you define a android:padding value, then it’ll take precedence over any edge-specific values, such as paddingLeft and paddingTop, but it won’t override paddingStart or paddingEnd.
  • android:paddingBottom. Adds extra space to the bottom edge.
  • android:paddingEnd. Adds extra space to the end edge.
  • android:paddingHorizontal. Adds extra space to the left and right edges. If you define a android:paddingHorizontal value then it’ll take precedence over paddingLeft and paddingRight, but not paddingStart or paddingEnd.
  • android:paddingLeft. Adds extra space to the left edge.
  • android:paddingRight. Adds extra space to the right edge.
  • android:paddingStart. Adds extra space to the start edge.
  • android:paddingTop. Adds extra space to the top edge.
  • android:paddingVertical. Adds extra space to the top and bottom edges. If you define a android:paddingVertical value, then it’ll take precedence over paddingTop and paddingBottom.

Margins: Adding space around your Views

While padding is applied between the edges of the View and the View’s contents, margins are applied outside of the View’s bounds. You can use margins to create space between your Views, or to create space between a View and the screen’s borders.

If your app contains multiple interactive UI elements, then margins can help ensure the user always activates the correct control, particularly for users who have manual dexterity issues.

Android provides the following margin attributes:

  • android:layout_margin. Adds extra space to the left, top, right and bottom sides of a View, for example android:layout_marginRight=”10dp.” If you define a layout_margin value, then it’ll take precedence over any edge-specific values.
  • android:layout_marginBottom. Adds extra space to the bottom side of the View.
  • android:layout_marginEnd. Adds extra space to the end side of the View.
  • android:layout_marginHorizontal. Adds extra space to the left and right sides of the View. Declaring a layout_marginHorizontal value is equivalent to declaring a layout_marginLeft and a layout_marginRight value. A layout_marginHorizontal value will take precedence over any edge-specific values.
  • android:layout_marginLeft. Adds extra space to the left side of the View.
  • android:layout_marginRight. Adds extra space to the right side of the View.
  • android:layout_marginStart. Adds extra space to the start side of the View.
  • android:layout_marginTop. Adds extra space to the top side of the View.
  • android:layout_marginVertical. Adds extra space to the top and bottom sides of the View. Declaring a layout_marginVertical value is equivalent to declaring a layout_marginTop and a layout_marginBottom value. A layout_marginVertical value will take precedence over any edge-specific values.

What Android Views can I use?

Now we’ve covered some common layout attributes, let’s take a closer look at some of the Views that are provided as part of the Android SDK.

Displaying text, with TextViews

You use TextViews to display text to your users, including interactive text such as hyperlinks, email addresses and phone numbers.

To create a TextView, simply add a <TextView> element to your layout resource file, and then specify your text using the android:text attribute and a string:

Code

<TextView
        android:id="@+id/hello_world"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:text="@string/helloWorld" />

If required, you can set or modify the View’s text at runtime, from your project’s Java code:

Code

public class MainActivity extends Activity {

    protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_main);
         final TextView helloWorldTextView = (TextView) findViewById(R.id.hello_world);
         helloWorldTextView.setText(R.string.new_text);
     }
 }

You can also style your text, using elements such as android:textColor, android:fontFamily, and android:textStyle, which has possible values of bold, italic, and bolditalic.

EditTexts: Creating editable, interactive text

EditText is an extension of the TextView class, which allows users to enter text into the View or modify the View’s existing text. Some common examples of EditTexts include login forms where the user can enter their email address and password, and forms where you can enter your payment details.

A login form created using two EditTexts and a Button

Sometimes, an EditText will only accept a certain type of text input, such as a phone number, password, or email address. You can often improve the user experience by declaring the expected input type, which will affect the default keyboard that’s displayed to the user. For example, if your EditText accepts a phone number, then you can use android:inputType=”phone” to display the numerical keyboard and make it easier for the user to enter that telephone number.

Code

<EditText
    android:id="@+id/phoneNumber"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:inputType="phone" />

Android supports a list of inputTypes, including some that specify additional behavior, for example android:inputType=”textPassword” automatically masks the user’s input, which reduces the chances of someone spying on their password.

Depending on the expected input type, you may be able to further streamline the user experience by combining inputType values with attributes that define additional behaviour, such as whether to provide spelling suggestions, or automatically capitalize new sentences. For example, if you wanted your EditText to capitalize the first word of a sentence and auto-correct spelling mistakes, then you’d use the following:

Code

android:inputType=
        "textCapSentences|textAutoCorrect

By default, Android’s virtual keyboard provides a user action button, such as a Next or Done button. However, these default actions aren’t always appropriate for the currently-selected EditText, for example if your EditText is a search field, then a Search action makes much more sense than Next or Done.

You can specify an alternative action for your EditText, using the android:imeOptions attribute and one of the many supported values, such as an actionSearch which performs a Search operation using the EditText’s contents.

Finally, sometimes you may want to be notified when the user changes the contents of your EditText. For example if your password EditText requires a password that’s at least ten characters long and features a mixture of letters, symbols and numbers, then you can improve the user experience by automatically checking the user’s input as they’re typing and then notifying them of any issues with their password, before they hit the Register button. You can register to receive these callbacks, by adding a TextWatcher to your EditText.

Displaying PNGs, JPGs and GIFs

You can use the ImageView class to display images. These images can be drawables that you instantiate from an image resource that’s saved in your project, or they can be images that your app downloads over the device’s Internet connection.

To instantiate a drawable from an image resource, you need to add a PNG, JPG or GIF to your project’s res/drawable directory and then reference that file from your XML layout. You’ll need to use the image’s file name as its resource ID, so if you had a file named scenery.jpg then you’d display that image using the following:

Code

<ImageView
         android:id="@+id/myImage"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:src="@drawable/scenery" />

The following screenshot shows this scenery drawable, rendered in Android Studio:

You can display a drawable by adding an ImageView to your layout

Alternatively, in Android 5.0 (API level 21) and higher you can use vector drawables, which define an image as a set of points, lines, and curves. Vector drawables can be scaled without loss of display quality, so you can use a single file for all of Android’s different screen densities.

Creating a custom vector drawable is beyond the scope of this tutorial, but you can get a taste for working with vectors, by taking a look at Vector Asset Studio, which is included as part of Android Studio.

You can use Vector Asset Studio to quickly and easily add any of the stock Material design icons to your project, in vector drawable format:

  • In Android Studio, Control-click your project’s drawable folder.
  • Select New > Vector Asset.
  • In Asset type, select Clip Art.
  • Select the Clip Art button, which displays the Android logo by default.
  • Choose any of the Material design icons; I’m using “done.”
Create a vector asset drawable, using the Vector Asset Studio
  • Give this asset a descriptive name, and then click Next.
  • Read the onscreen information, and if you’re happy to proceed then click Finish.
  • Open your project’s drawable folder and you should see a new XML file that defines your chosen Material icon as a vector drawable. Here’s the contents of my vector drawable resource:

Code

<vector xmlns:android="http://schemas.android.com/apk/res/android"
       android:width="24dp"
       android:height="24dp"
       android:viewportWidth="24.0"
       android:viewportHeight="24.0">
   <path
       android:fillColor="#FF000000"
       android:pathData="M9,16.2L4.8,12l-1.4,1.4L9,19 21,7l-1.4,-1.4L9,16.2z"/>
</vector>

You then just need to reference this vector drawable in your ImageView, in exactly the same way you’d reference a standard drawable resource, for example  android:src=”@drawable/done_vector.”

Buttons and ImageButtons

Buttons and ImageButtons are Views that listen for clicks and then call a method in your code every time the user interacts with that button.

You can communicate the action that’ll occur when the user interacts with your button, using a text label, an icon, or a text label and an icon.

In the following snippet, we’re creating a Button that features a text label:

Code

<Button
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:text="@string/button_label"/>

To create an ImageButton, you’ll need to add an image file to your project and then reference it in exactly the same way you referenced your drawables in the previous section. For example:

Code

<ImageButton
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/button_icon"/>

If you want to create a button that features an image and a text label, then you’ll need to add a text label as normal, and then reference your drawable using one of the following attributes:

  • android:drawableLeft. Position the drawable to the left of the text.
  • android:drawableRight. Position the drawable to the right of the text.
  • android:drawableStart. Position the drawable to the start of the text.
  • android:drawableEnd. Position the drawable to the end of the text.
  • android:drawableTop. Position the drawable above the text.
  • android:drawableBottom. Position the drawable below the text.

Here, we’re creating a button_icon drawable and placing it at the start of the Button’s button_label text:

Code

<Button
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:text="@string/button_label"
   android:drawableStart="@drawable/button_icon"/>

In addition to adding labels and images, you can customize your Buttons and ImageButtons by adding a background image or a color resource, using the android:background attribute. For example, you can turn a button blue, by adding the following to your Button or ImageButton declaration:

Code

android:background="#0000FF"

Whenever the user interacts with a button, that Button or ImageButton will receive an onClick event. You’ll need to define a handler for this event, using the android:onClick attribute.

The value of the onClick attribute must correspond to a public method, which will be called in response to the onClick event, for example:

Code

<Button
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:text="@string/button_label"
   android:onClick="displayToast" />

Next, you’ll need to implement this method in the Activity that’s hosting your Button or ImageButton. This method must be public, return void, and define a View as its only parameter, for example:

Code

public void displayToast(View view) {
       Toast.makeText(MainActivity.this,
               "Your Message", Toast.LENGTH_LONG).show();

   }

}

Alternatively, you can declare an event handler programmatically. In Java, this means creating an View.OnClickListener object and then assigning it to the Button or ImageButton, using setOnClickListener(View.OnClickListener).

Give your users options, with CheckBoxes

CheckBoxes allow the user to choose one or more options from a vertical list.

CheckBoxes allow you to create vertically-scrolling lists of options.

You create a CheckBox by adding a <Checkbox> item to your XML layout:

Code

<CheckBox android:id="@+id/yes"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/yes"
        android:onClick="onCheckboxClicked"/>

Since CheckBoxes typically allow the user to select multiple items, you’ll need to add an android:onClick attribute to each individual <CheckBox> element, and then reference the method that’ll be called in response to CheckBox click events.

When you implement the corresponding method in your hosting Activity, you’ll need to verify which CheckBox was selected, and then perform an appropriate action depending on the user’s selection. For example, if we created Yes and No CheckBoxes, then we’d add the following to our hosting Activity:

Code

public void onCheckboxClicked(View view) {
    boolean checked = ((CheckBox) view).isChecked();

//Verify which checkbox is selected//

    switch(view.getId()) {
         case R.id.yes:

//If the “yes” checkbox is selected, then...//

            if (checked)

//Do something//

            else
            Break;

//If the “no” checkbox is selected, then….//

        case R.id.no:

            if (checked)

//Do something//

Views and ViewGroups: Creating RadioButtons

RadioButtons allow the user to choose from a set of mutually-exclusive options, such as the Agree/Disagree buttons commonly found on Terms and Conditions forms.

RadioButtons allow users to choose one or more options from a vertical list

You create each RadioButton by adding a <RadioButton> element to your layout. Since RadioButtons are mutually exclusive you’ll need to arrange all of your <RadioButton> elements inside a <RadioGroup> ViewGroup, which ensures that only one RadioButton can be selected at a time.

Code

<?xml version="1.0" encoding="utf-8"?>
<RadioGroup xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">
    <RadioButton android:id="@+id/radio_confirm"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/confirm"
        android:onClick="onRadioButtonClicked"/>
    <RadioButton android:id="@+id/radio_deny"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/deny"
        android:onClick="onRadioButtonClicked"/>
</RadioGroup>

You define a click handler by adding the android:onClick attribute to every RadioButton in your RadioGroup, and then implementing the corresponding method in your hosting Activity. Similar to our CheckBox example, this method needs to verify which RadioButton is currently selected, and then take appropriate action based on the user’s selection.

Code

public void onRadioButtonClicked(View view) {
    boolean checked = ((RadioButton) view).isChecked();

//Verify which RadioButton is selected//

    switch(view.getId()) {

//If the “confirm” radio button is selected, then...//

        case R.id.radio_confirm:

            if (checked)

//Do something//

            Break;

//If the “deny” button is selected, then...//

         case R.id.radio_deny:

             if (checked)

//Do something//

Spinner

When tapped, a Spinner displays a set of values as a dropdown menu.

An Android Spinner displays a set of values as a dropdown menu.

The user can tap any item in the Spinner, and your application will perform an action based on their selection. By default, a Spinner always displays the currently-selected value.

A functioning Spinner consists of several components:

  • A <Spinner> element that you add to your layout resource file.
  • A data source that supplies your Spinner with some information; I’ll be using a simple String Array.
  • An ArrayAdapter that converts your data into View items, ready to be displayed in your Spinner.

Let’s start by adding a <Spinner> to our XML layout:

Code

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
   xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   tools:context=".MainActivity">

   <Spinner
       android:id="@+id/location_spinner"
       android:layout_width="fill_parent"
       android:layout_height="wrap_content" />

</LinearLayout>

If the data is predetermined, then you can provide it as a String Array that’s defined in your Strings.xml file:

Code

<resources>
   <string name="app_name">SimpleSpinner</string>
       <string-array name="location_array">
           <item>Argentina</item>
           <item>Armenia</item>
           <item>Australia</item>
           <item>Belgium</item>
           <item>Brazil</item>
           <item>Canada</item>
           <item>China</item>
           <item>Denmark</item>
           </string-array>
           </resources>

You can then deliver this Array to your Spinner using an instance of ArrayAdapter, which you implement in an Activity or Fragment.

To define an ArrayAdapter, we need to complete the following steps:

  • Create an ArrayAdapter from the String Array, using the createFromResource() method.
  • Specify a layout resource that defines how the user’s chosen item should appear in the Spinner. Android provides a simple_spinner_item layout that you should use unless you specifically require a custom layout.
  • Use setDropDownViewResource(int) to specify which layout the Adapter should use for the Spinner dropdown menu. Once again, Android provides a ready-made layout (simple_spinner_dropdown_item) that should be suitable for most projects.
  • Apply the Adapter to your Spinner, by calling setAdapter().

Here’s my completed code:

Code

Spinner spinner = (Spinner) findViewById(R.id.location_spinner);

//Create an ArrayAdapter//

ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this,

//Populate the spinner using the String Array and the simple_spinner_item layout//

        R.array.location_array, android.R.layout.simple_spinner_item);

//Specify the layout that should be used for the dropdown menu//

adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

//Apply the Adapter to the Spinner//

spinner.setAdapter(adapter);

The Spinner will receive an onItemSelected event every time the user selects an item from the dropdown. To process this event, you’ll need to use the AdapterView.OnItemSelectedListener interface to define an onItemSelected() callback method.

In the following code, I’m displaying a toast every time onItemSelected() is invoked, and incorporating the name of the newly-selected item into my toast. I’m also defining a onNothingSelected() callback method, as this is also required by the AdapterView.OnItemSelectedListener interface.

Here’s the completed Activity:

Code

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener {

   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);

       Spinner spinner = (Spinner) findViewById(R.id.location_spinner);
       spinner.setOnItemSelectedListener(this);

       ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this,

               R.array.location_array, android.R.layout.simple_spinner_item);
                   adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
       spinner.setAdapter(adapter);

   }

   public void onItemSelected(AdapterView<?> parent, View view,
                   int pos, long id) {

       Toast.makeText(parent.getContext(),
               "You've selected n" + parent.getItemAtPosition(pos).toString(),
               Toast.LENGTH_LONG).show();
   }

   @Override
   public void onNothingSelected(AdapterView<?> adapterView) {

//To do//

   }
}

ListViews: Displaying your data as scrollable lists

A ListView displays a collection of items as a vertically-scrolling, single column list. When the user selects an item from a ListView, your app will typically perform an action, such as displaying additional information about the selected item.

Android's ListView displays a collection of items as a vertically-scrolling, single column list.

To create a ListView, you’ll need to add a <ListView> element to your XML layout resource file, and then create an Adapter, which will handle the process of displaying each item in your ListView.

Let’s start by adding a <ListView> to our layout:

Code

<?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <ListView android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:id="@+id/myListView">
    </ListView>

</LinearLayout>

A ListView requests Views on-demand from its assigned Adapter. In our MainActivity, we need to create an Adapter and then associate it with our ListView, using setAdapter(android.widget.ListAdapter).

Code

import android.app.Activity;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.os.Bundle;
import android.widget.ListView;
import android.view.View;
import android.widget.Toast;

public class MainActivity extends Activity {

    String[] countryArray = {"Argentina" , "Armenia", "Australia", "Belgium" ,"Brazil" ,"Canada" , "China" ,
            "Denmark" , "Estonia" , "Finland" , "France" , "Greece" , "Hungary" , "Iceland" , "India" ,
            "Indonesia" , "Italy" , "Japan" , "Kenya" , "Latvia"};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final ListView listView = (ListView)findViewById(R.id.myListView);

 ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1, countryArray);
   listView.setAdapter(adapter);

        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Toast.makeText(parent.getContext(),
                        "You've selected n" + parent.getItemAtPosition(position).toString(),
                         Toast.LENGTH_LONG).show();

            }
        }
        )
                ;
    }}

Designing unique experiences: Creating custom Views

While there’s no shortage of built-in Views, sometimes you may have very specific requirements that aren’t met by any of Android’s built-in Views. In this scenario you can create your own, custom Android Views.

Most of the time, you’ll create a custom View by identifying a built-in View that almost meets all of your requirements, and then extend this View with your own modifications. However, it’s also possible to create a View from scratch, by extending the base View class.

Creating a custom View is an advanced topic that requires you to complete multiple steps, including providing overrides for the methods that Android usually calls automatically, such as onDraw() and onTouchEvent(), but custom Views can be an effective way to deliver unique experiences to your users.

Wrapping up

In this article, we explored all of the most commonly-used Android Views, plus some of the key attributes you’ll use when creating these Views.

Are there any Views you’d like us to explore in more detail? Let us know in the comments below!

Большинство из нас чувствует себя неуверенно, когда приходится знакомиться с новой операционной системой. И несмотря на то, что Андроид сегодня можно встретить на подавляющем числе электронных устройств, всё же есть много пользователей не знакомых с ним.

Знакомство с функциями Android

Множество возможностей системы пользователи никогда не используют

Если вы являетесь одним из таких людей, мы предоставим вам самую важную информацию о том, как разобраться в системе, познакомим с её главными функциями. В общем, перед вами своеобразная инструкция под названием «Андроид для чайников», где собраны все актуальные советы по работе с платформой.

Содержание

  • 1 Начало пользования системой Андроид
    • 1.1 Включаем устройство, заходим в свой аккаунт и устанавливаем соединение с интернетом
  • 2 Что представляет собой интерфейс системы?
  • 3 Пользование интернетом на Андроид
    • 3.1 Как зайти в интернет на Андроид?
  • 4 Как работать с клавиатурой?
    • 4.1 Как добавить другие языки на клавиатуру?
  • 5 Как пользоваться Google Play Market?
  • 6 Файловый менеджер и как смотреть фильмы и слушать музыку на Андроид
  • 7 Как установить мелодию на звонок?

Начало пользования системой Андроид

Включаем устройство, заходим в свой аккаунт и устанавливаем соединение с интернетом

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

  • Выбрать язык интерфейса.
    Выбор языка для настроек
  • Подключится к интернету через Wi-Fi — если у вас нет поблизости сети, то этот шаг можно пропустить. Почему это меню появляется при первом же включении? Из-за того, что большинство программ разработаны для использования при рабочем интернет-подключении. Это вовсе не значит, что телефон или планшет бесполезен без интернета, подобный шаг создан скорее для удобства — мол, подключитесь к нему сразу, чтобы потом об этом не беспокоиться.
    Выбор беспроводной сети
  • Далее системный мастер предложит зайти в ваш Google-аккаунт или создать его, если вы ещё не обзавелись учётной записью. Крайне советуем завести себе аккаунт, ведь сама система Андроид сильно привязана к сервисам компании Google. Без него вы не зайдёте в магазин приложений, не сможете пользоваться почтой. Кроме того, учётную запись создать нетрудно, зато она всегда будет с вами на всех устройствах, где вы только пожелаете, что довольно удобно.
    Создание Google-аккаунта
  • В следующем меню вам нужно подтвердить время и дату, которые практически всегда определяются автоматически, либо ввести их вручную.
    Подтверждение даты и времени
  • В последнем окне вы увидите пункты, касающиеся определения вашего местоположения — лучше не выключать их, чтобы все сервисы правильно работали и смартфон верно определял время и дату.

Передача данных о местоположении

Что представляет собой интерфейс системы?

После настройки своего смартфона или обычного включения устройства, даже если вы не проходили работу с мастером, вы увидите рабочий стол вашего гаджета.

Рабочий стол Android

Что он собой представляет? Вам будут предложены следующие символы и иконки:

  • Время и дата — у вас могут отображаться отдельные часы или календарь, или эти данные будут расположены в правом нижнем углу, как это чаще всего принято на планшетах.
  • Снизу в большинстве случаев размещены три знака — кнопка назад, главное меню и контекстное меню, где отображаются запущенные приложения.
    Функциональные клавиши системы
  • На рабочем столе, как правило, размещаются самые важные и наиболее используемые программы. Их можно удалить — просто нажмите и задержите палец на программе, через пару секунд значок станет перемещаемым и его можно будет перетянуть на крестик.
  • Рабочих столов может быть несколько — они перемещаются при выполнении перелистывающих движений по экрану, при желании их тоже можно добавить или удалить — убирается виджет так же, как и отдельная программа. Чтобы добавить ещё один рабочий стол, коснитесь 2 пальцами экрана и сведите их, после чего появится плюсик — на него и следует нажать.
    Управление рабочими столами
  • На рабочие столы можно добавлять программы из общего списка меню. Где его найти? Нажмите главную клавишу на планшете или смартфоне, или на среднюю кнопку внизу экрана — о ней мы уже упоминали. Когда перед вами откроется список, вы можете выбрать один из элементов, зажать палец на той части экрана, где он расположен, после чего его можно передвинуть на любое место рабочего стола.

Программы на рабочем столе

Стоит отметить, что на планшетах с Андроидом в нижней строке открывается быстрое меню, где вы можете включить Wi-Fi, узнать о заряде батареи и прочей важной информации — чтобы открыть его, просто сделайте движение снизу вверх в области часов. В смартфонах под управлением этой системы для открытия меню уведомлений нужно провести пальцем по всему экрану сверху вниз.

Значки Android

Мы рассмотрели, как выглядит рабочий стол, теперь перейдём к основному меню Android.

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

Пользование интернетом на Андроид

Если вы уже установили подключение к интернету, самое время узнать, как пользоваться браузером. В случае, когда Wi-Fi выключен, активировать его вы можете в упомянутом меню уведомлений или через настройки, которые вы найдёте в меню. После того как вы откроете раздел беспроводного соединения, активируйте работу Wi-Fi, затем, устройство выполнит автоматический поиск сетей. Дело остаётся за малым — выбрать сеть из списка, ввести пароль, если это необходимо и нажать «Подключить».

Как зайти в интернет на Андроид?

Для этого следуйте таким инструкциям:

  • Выберите установленный в смартфоне или планшете браузер, откройте его.
  • Далее вы можете пользоваться браузером таким же образом, как и на компьютере — перед вами будет строка для ввода адреса, возможность добавлять вкладки, а в дополнительных иконках скрываются меню для добавления закладок, просмотра истории посещений страниц и прочее.

Запуск мобильного браузера

В целом ничего сложного в работе с браузером на планшете или смартфоне нет — если вы не знаете некоторых функций или значков, просто попробуйте их.

Мы упустили только один момент — чтобы ввести адрес сайта, вам нужна клавиатура.

Как работать с клавиатурой?

Клавиатура будет автоматически открываться всякий раз, когда вы будете нажимать на строку, где вводится тот или иной текст, сообщение. Поэтому её запуск — дело нехитрое, а если нужно убрать средство ввода просто нажмите «Назад».

О работе с клавиатурой стоит знать следующее:

  • Расположение клавиш здесь такое же, как и на компьютерной клавиатуре.
  • Значок глобуса служит для смены языка ввода.
  • Прозрачная стрелка меняет клавиши на заглавные, если нажать два раза подряд — включится режим Caps Lock.
  • Стрелка с крестиком стирает символы, большая кнопка справа служит для переноса курсора вниз — как компьютерная клавиша Enter.
  • Чтобы переместить курсор, прикоснитесь к необходимой области на экране.
  • На некоторых клавишах размещены несколько символов — чтобы выбрать дополнительный, а не основной знак, просто немного придержите палец на нём.
    Стандартная клавиатура Android
  • Как правило, под буквами на клавиатуре размещены кнопки для её переключения на цифровую раскладку или список с символами — просто нажимайте на неё, чтобы открыть нужный набор знаков.
  • Если вам нужно выделить текст и скопировать, вырезать или переместить его, выполните длинное нажатие на строке, где начинается нужный вам кусок, после чего появятся две стрелки. Растягивая их, вы можете выделить необходимое количество символов, а в верхнем меню выбрать операцию для выделенного текста.

Редактирование текстовых документов

Как добавить другие языки на клавиатуру?

Делается это в настройках, где есть меню, посвящённое средствам ввода — в нём вы можете добавлять языки, включать или выключать словари, выполнять прочую настройку клавиатуры.

Добавление языков и словарей

В планшетах настройки средства ввода доступны в нижней строке, рядом с часами — соответствующий символ в виде точек появляется при каждом включении клавиатуры, поэтому можно даже не заходить в меню и не искать нужный раздел в настройках.

Как пользоваться Google Play Market?

Этот сервис представляет собой приложение, где вы найдёте тысячи всевозможных программ для вашего устройства с Android. Как правило, Play Market есть по умолчанию в меню вашего планшета или смартфона, для пользования им нужна учётная запись Google — если ранее вы не выполняли вход, то сделаете это при первом запуске магазина.

Итак, как пользоваться этим чудом? Всё очень просто — выбираете понравившееся приложение или находите его через строку поиска, нажимаете «Установить», а далее оборудование справится со всем самостоятельно.

Приложения в Play Market

Если вам нужно удалить программу или перенести её на карту памяти — последнее необходимо, когда на самом устройстве мало места, а сделать это вы можете в настройках. В отдельном разделе вынесены все приложения, установленные на вашем гаджете.

Файловый менеджер и как смотреть фильмы и слушать музыку на Андроид

Для просмотра файлов мультимедиа есть отдельное приложение под названием Галерея или Хранилище Мультимедиа, которое вы найдёте в главном меню. Ничего сложного в пользовании им нет, по созданным папкам распределяются фотографии, видео, находящиеся в памяти устройства или на карте.

Если же вам нужны аудиофайлы, книги и общий список файлов на устройстве — для этого существует файловый менеджер, который на системе Андроид имеет название Проводник.

Мультимедийные файлы в галерее

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

Как установить мелодию на звонок?

Если вы пользуетесь смартфоном на Андроид, то наверняка хотите слышать любимую мелодию на звонке. Делается это через настройки — зайдите в меню Звук, нажмите на строку Мелодия звонка, где вы сможете выбрать необходимый файл. Как видите, в этом меню вы можете полностью редактировать настройки звонков. Установить понравившуюся мелодию вы можете и в плеере при прослушивании музыки — в меню вы найдёте соответствующую функцию.

Установка мелодии на звонок

Благодаря этой краткой инструкции по Android вы узнали минимальный набор самых важных разделов и настроек системы, которые позволят начать своё уверенное пользование смартфоном или планшетом. Главное — не бойтесь пробовать и узнавать то, чего вы раньше не видели. В целом же пользование этой платформой наверняка будет для вас простым и понятным, ведь в ней всё продумано логично и последовательно.

16 марта 2015

Перед вами своеобразный путеводитель по миру Android для новых пользователей устройств на этой ОС. В первой части материала речь пойдет о первичной настройке Android смартфона, логике работы его интерфейса и установке новых программ.

Android_для_чайников_1_main

Вместо предисловия

О формате статьи

С лета прошлого года в нашем блоге еженедельно публиковались короткие заметки из серии «Android для чайников». В них мы постарались доступным языком рассказать новым пользователям Android все самое важное об этой ОС. Как настроить Android смартфон, как скачать новые приложения, как избежать быстрого разряда батареи, как восстановить забытый пароль к экрану блокировки и многое другое.

Информации набралось больше, чем мы рассчитывали изначально, найти ответ на свой вопрос в нескольких десятках заметок новым пользователям было совсем не просто. Поэтому все эти заметки будет объединены в пару больших статей, которые будут представлять из себя что-то вроде первого гайда для «чайников».

О многообразии Android устройств

Android — открытая операционная система, на базе которой работают тысячи самых разных устройств от сотен различных фирм. Зачастую производители немного изменяют стандартный интерфейс Android, заменяют стандартные компоненты системы на фирменные приложения и чуть иначе группируют пункты в меню настроек. Так что, вполне возможно, что интерфейс вашего смартфона будет отличаться от того, что вы видите на скриншотах, а несколько пунктов меню будут иметь немного другое название.

Бояться этого не стоит — логика работы Android в подавляющем большинстве фирменных оболочек не меняется, и научившись работать с одним Android аппаратом, вы без всякого труда разберетесь с любым другим. Стационарный компьютер и ноутбук на первый взгляд тоже совершенно разные устройства. Но я еще не встречал человека, который умел бы работать в Windows на ноутбуке, но не смог разобраться с той же Windows на ПК.

Часть первая. Первый запуск

Мастер первого запуска

Когда вы включите только что купленный аппарат первый раз, то увидите на экране мастер первого запуска. Он поможет вам выполнить первичную настройку телефона, избавив от необходимости копаться в непонятных меню.

На первом шаге вам предложат выбрать язык интерфейса и подключиться к Wi-Fi сети. Если ни одной точки доступа Wi-Fi поблизости нет, то можно воспользоваться мобильным интернетом от вашего сотового оператора.

Android_для_чайников_1-19Android_для_чайников_1-20

Android_для_чайников_1-21Android_для_чайников_1-22

Здесь стоит отметить, что любой современный смартфон, будь то аппарат на Android, iOS или Windows Phone, изначально рассчитан на использование интернета. Безусловно, никто не мешает пользоваться им и без доступа к сети, вот только множество интересных возможностей и полезных функций в этом случае будут вам недоступны. Например, какой смысл от прогноза погоды на главном экране, если он не обновляется неделями? Зачем настраивать на смартфоне почту, если проверить без интернета вы ее все равно не сможете? И много ли толку от чата или клиента любимой социальной сети, в которых не появляется новых сообщений?

У каждого оператора мобильной связи свои тарифы на интернет, которые различаются по стоимости и параметрам. Все их можно условно разделить на две группы — тарифы с пакетом предоплаченного трафика и тарифы, на которых вы платите за израсходованный трафик по факту. И я крайне рекомендую перейти на тарифный план с каким-то включенным объемом трафика, пусть даже и совсем небольшим. Дело в том, что в тарификации мобильного интернета есть один большой подводный камень, который называется «округление трафика». Даже если ваш смартфон «вылез» в интернет на долю секунды и израсходовал на проверку погоды всего пару килобайт, оператор связи все равно округлит это число до какого-то минимально допустимого значения. И иногда это «минимально допустимое значение» может составлять целый мегабайт, что на некоторых тарифных планах может обойтись вам в 5-10 рублей за одно подключение. Что, мягко говоря, совершенно невыгодно. А вот «условно-безлимитные» пакетные предложения от таких проблем избавляют раз и навсегда.

На втором шаге система попросит зайти в существующий Google-аккаунт или создать новый. Аккаунт Google — ваш персональный ключ к самым полезным и интересным возможностям смартфона. Практически все сервисы Google без него работать не будут — а это и фирменный магазин приложений, и синхронизация контактов в облаке, и почта Gmail, и диск Google Drive, и много что еще. Аккаунт Google останется с вами навсегда, даже после того, как вы решите сменить свой старый Android смартфон на новый. А вместе с ним — все ранее купленные приложения, контакты и даже некоторые данные и настройки. Отнеситесь к этому шагу максимально внимательно и постарайтесь не забыть логин и пароль.

Android_для_чайников_1-23Android_для_чайников_1-24

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

Android_для_чайников_1-28Android_для_чайников_1-27

Перенос контактов со старого аппарата

На этом первичная настройка смартфона закончена и им можно пользоваться. Вопрос только в том, как перенести на него контакты с прошлого телефона.

Если это не первый ваш Android смартфон, то все контакты, скорее всего, уже и так хранятся в облачном сервисе Google. Если, конечно, на вашем старом смартфоне вы не отключали их синхронизацию.

Проверить, сохранились ли в Google ваши контакты, можно прямо с компьютера. Для этого нужно зайти в почту Gmail и в левом верхнем углу выбрать пункт «Контакты».

Чайник_17-02Чайник_17-01

Если вы «переезжаете» со смартфона, работающего на какой-то иной платформе, то перенести контакты можно двумя способами. Первый способ — записать их на SIM-карту. Еще несколько лет назад им пользовалось большинство людей и он всех устраивал. А вот на сегодняшний день такой способ уже заметно устарел. Во-первых, далеко не факт, что у вашего старого телефона и нового Android смартфона совпадает формат SIM-карты. К примеру, в старом аппарате могла использоваться стандартная miniSIM-карта, а в новом — уже ее micro- или даже nano- аналог. А значит, старую SIM-карту просто так в смартфон не переставишь. Во-вторых, обычно на SIM-карту можно записать только контакты самого простого формата: «одно имя — один телефон». А это тоже не всем и не всегда может быть удобно.

Второй способ — экспортировать контакты из старого телефона в виде vCard (.*vcf файлов). Такой способ поддерживает большинство имеющихся на рынке моделей, хотя досадные исключения тоже все еще попадаются. Далее *vcf файл можно записать на microSD карту или передать на смартфон любым другим образом. Например, с помощью почты.

Для импорта vCard контактов в новый смартфон нужно открыть его адресную книгу, нажать на кнопку «Меню», зайти в раздел «Управление контактами» и выбрать пункт «Экспорт и импорт». Отсюда можно как сохранить контакты на карту памяти, так и восстановить их из резервной копии.

Android_для_чайников_1-17Android_для_чайников_1-18

Android_для_чайников_1-16Android_для_чайников_1-15

Подробнее о резервном копировании и переносе личных данных (контактов, фотографий, SMS) в новый смартфон вы узнаете из семнадцатого выпуска нашей колонки.

Настройка почты

Следующий момент — настройка почты. Если вы пользуетесь почтой Gmail, то она была автоматически настроена в тот момент, когда вы ввели данные своего Google аккаунта. А вот если у вас есть свой ящик на каком-то ином почтовом ресурсе, то придется настроить его вручную.

Прежде всего отмечу, что на большинстве смартфонов для работы с почтой Gmail и для работы с остальной почтой используют разные почтовые программы. Так сложилось исторически — почта Gmail предлагала своим пользователям ряд возможностей, которые многими другими почтовыми серверами не поддерживались. Поэтому в компании решили создать для своей почты отдельный клиент, который был бы максимально адаптирован под функции Gmail. Сейчас никакой особой необходимости в таком разделении уже нет, и в Google потихоньку приходят к тому, чтобы разрешить пользователям подключать к «родному» почтовому клиенту ящики с других серверов.

Сама по себе настройка почтового клиента чрезвычайно проста, главное — знать названия серверов для отправки и приема почты, которые используются в вашем почтовом ящике.

Рассмотрим настройку почты на примере почтового клиента в прошивке MIUI. Настройка иных программ для работы с почтой будет практически идентична.

На первом шаге нужно ввести название почтового ящика и пароль, а также выбрать протокол для приема почты. В основном почтовыми сервисами поддерживается два протокола — POP3 и IMAP. Первый протокол наиболее распространен и позволяет просто копировать хранящуюся на сервера почту в телефон. Второй протокол умеет чуть больше и позволяет работать с почтой прямо на удаленном сервере. Если используемый вами почтовый сервис поддерживает оба варианта – лучше выбирать IMAP.

Чайник_31-04Чайник_31-03

После того, как настройки введены, остается нажать на кнопку «Вход». В идеале программа сама подберет все необходимые настройки и подключится к вашему почтовому ящику. Но на практике так происходит далеко не всегда. Если подключение не удалось, то нужно нажать на кнопку «Вручную» и самостоятельно ввести все необходимые данные. Найти их можно в разделе помощи в веб-интерфейсе вашего почтового ящика.

Чайник_31-02Чайник_31-01

Особое внимание обратите на имя пользователя. Иногда здесь нужно указывать полное название почтового ящика, а иногда только его первую часть, которая идет до символа «@». Например, вот так выглядят настройки для mail.ru:

Чайник_31-05

Экранная клавиатура

Как вы могли заметить, и при настройке, и при повседневной работе со смартфоном приходится очень часто пользоваться экранной клавиатурой. У тех пользователей, которые впервые купили телефон с сенсорным экраном, она может вызвать ряд затруднений.

В Android вам никогда не придется задумываться над тем, как именно вызвать клавиатуру. Просто нажмите на текстовое поле или окно, в котором необходимо ввести текст, и клавиатура автоматически появится на экране. Если она мешает – нажмите на телефонную кнопку «Назад» и она вновь исчезнет.

Чайник_15-03Чайник_15-06

Сам процесс ввода текста мало чем отличается от печати на клавиатуре ПК или ноутбука. Рассмотрим его на примере клавиатуры Google.

В стандартной клавиатуре Google сменить язык ввода можно с помощью кнопки со значком глобуса Чайник_15-05_a.

В некоторых других клавиатурах для этого используется горизонтальный свайп по клавише пробела либо долгий тап по ней же. Указать, какие именно языки следует «повесить» на переключатель, обычно можно в настройках клавиатуры.

Для того, чтобы ввести заглавную букву, необходимо нажать на клавишу Shift Чайник_15-01_a. Удерживая ее и продолжая печать, можно ввести несколько заглавных букв подряд. Двойное нажатие по клавише Shift переведет клавиатуру в режим Caps Lock, во время которого все набранные буквы будут заглавными.

Если нужно стереть неверно введенное слово, воспользуйтесь клавишей удаления текста Чайник_15-04_a. При одиночном нажатии на клавишу будет удален один символ, находящийся слева от курсора. Удерживая клавишу удаления, можно быстро удалить одно или несколько слов. Будьте внимательны – чем дольше вы удерживаете клавишу, тем больше возрастает скорость, с которой стирается текст.

В случае, когда требуется переместить курсор в другое место, просто дотроньтесь пальцем до нужного места экрана. Иногда на клавиатурах также присутствуют специальные стрелки, позволяющие перемещать курсор в пределах активного текстового поля.

На некоторые клавиши нанесено сразу два символа, основной и дополнительный. Для ввода дополнительного символа нужно нажать и удерживать клавишу в течение пары секунд. Если дополнительных символов на клавише несколько, то для выбора нужного следует, не отрывая палец от экрана, выполнить в его сторону горизонтальный свайп. Таким же образом можно ввести буквы «Ъ» и «Ё», которых изначально нет на клавиатуре. Для этого достаточно выполнить долгий тап по клавишам «Ь» и «Е» соответственно.

Чайник_15-04Чайник_15-05

Кроме основного экрана, каждая клавиатура имеет как минимум парочку дополнительных, со служебными символами, цифрами и графическими смайликами. Клавиша переключения экранов обычно находится в нижнем углу клавиатуры.

В клавиатуре Google экран с дополнительными символами открывается с помощью кнопки Чайник_15-02_a в левом нижнем углу экрана, а список смайликов – с помощью долго тапа по клавише Enter Чайник_15-03_a.

Чайник_15-07Чайник_15-02

Во время ввода текста вверху клавиатуры будут выводиться подсказки. Тап по подсказке превращает введенные вами буквы в выбранное слово. Принцип, по которому работают подсказки, сильно различается у разных клавиатур. В некоторых случаях они годятся только для того, чтобы быстро исправить неверно введенное слово. В других случаях с их помощью можно набрать целое предложение, вообще избежав ручного ввода букв. Подробнее о популярных клавиатурах вы можете прочитать в материале «Кастомизация Android смартфона. Часть первая. Первые шаги».

В последнее время большинство клавиатур обзавелись поддержкой безотрывного ввода текста, больше известного как «Swype». При использовании этого метода ввода все слово набирается на клавиатуре одним движением, без отрыва пальца от экрана. Такой способ позволяет существенно сократить время печати.

Тем не менее, в некоторых ситуациях текст проще скопировать и вставить, чем вводить его вручную. Для выделения текста достаточно сделать долгий тап по нужному вам слову. Для того, чтобы изменить границы выделения, нужно потянуть за маркеры по его краям. Кнопки «Вырезать», «Копировать» и «Вставить» появятся в верхней части экрана либо прямо около курсора.

Чайник_15-01Чайник_15-08

Схожим образом происходит выделение и копирование текста из других приложений. Например, таким образом можно скопировать адрес открытого в веб браузере сайта или текст письма из почтового клиента.

Подключение к Wi-Fi

В заключение еще раз вернемся к теме Wi-Fi. Скорее всего, первое подключение к домашней Wi-Fi сети вы настроили еще во время первого запуска аппарата. Однако подключение к Wi-Fi может понадобиться вам не только дома, но и на работе, в институте или кафе. И тут встает вопрос — как подключиться к новой сети?

Ничего сложного в этом нет. Достаточно просто зайти в настройки телефона, а затем перейти в раздел «Wi-Fi».

Чайник_2-15Чайник_2-13

Вам откроется список доступных Wi-Fi сетей. Замочек рядом с иконкой Wi-Fi показывает, что сеть защищена паролем. Соответственно, при попытке подключения к такой сети смартфон запросит пароль.

Чайник_2-07Чайник_2-11
Чайник_2-12Чайник_2-08

По умолчанию большинство Android устройств настроено таким образом, что подключение к известной сети происходит автоматически. Иными словами, если вы хотя бы один раз подключили смартфон к какой-то Wi-Fi сети, то как только вы вновь попадете в радиус ее действия, смартфон подключится к ней самостоятельно. В большинстве случаев это удобно. Но иногда бывают ситуации, когда повторное подключение к конкретной сети нежелательно. В этом случае необходимо сделать долгий тап (нажать и удерживать в течение пары секунд) на названии нужной сети, затем выбрать пункт «Удалить сеть» либо «Забыть сеть». Кроме того, здесь можно исправить настройки сети, если у нее изменился тип шифрования или пароль.

В очень редких случаях нужная вам Wi-Fi сеть может не отображаться в списке доступных. Скорее всего, администратор сети специально сделал ее скрытой, чтобы подключиться к ней могли только те, кто знает ее название. Для подключения к такой сети достаточно нажать на кнопку «Меню», находящуюся в левом верхнем углу экрана, затем выбрать пункт «Добавить сеть».

С помощью этого же меню можно получить доступ к дополнительным настройкам Wi-Fi. Хотя пункты настроек на смартфонах разных производителей могут немного отличаться, основные опции присутствуют на всех аппаратах. Прежде всего, это настройка работы Wi-Fi в режиме сна и включение уведомлений о доступных открытых Wi-Fi сетях.

Чайник_2-10Чайник_2-09

Часть вторая. Интерфейс смартфона

Внешний вид интерфейса Android смартфона зависит не столько от версии ОС, сколько от фирменной оболочки, которую установил производитель устройства. Тем не менее, сама по себе организация рабочего пространства практически всегда остается неизменной. Исключения из этого правила бывают, но не слишком часто. В основном речь идет о японских или китайских смартфонах, с которыми неопытный пользователь вряд ли где-то столкнется.

Жесты

Управление любым смартфоном с сенсорным экраном происходит, в первую очередь, с помощью жестов, и Android здесь не исключение. Вот основные из них:

Тап — одиночное касание пальцем экрана, аналог клика мышкой. Например, фраза «тапните по иконке» означает, что нужно один раз коснуться ее пальцем и сразу убрать руку.

Двойной тап — быстрое двойное касание (или «постукивание») по экрану, этот жест похож на двойной клик мышью.

Долгий тап — долгое нажатие на экран, длящееся несколько секунд.

Свайп — скользящее движение пальцем по экрану, без отрыва пальца до завершения жеста. Так, фраза «горизонтальный свайп» обычно означает, что вам нужно провести пальцем по экрану слева направо.

Щипок — нужно коснуться экрана двумя пальцами, а затем свести их вместе. Или, напротив, развести в разные стороны. Таким способом обычно выполняется масштабирование изображения, карты или веб-страницы.

Рабочий стол и иконки док-бара

Рабочих столов в Android может быть несколько, «перелистывать» их можно с помощью горизонтального свайпа в любом направлении. Максимальное количество рабочих столов зависит от версии ОС и фирменной оболочки, обычно их может быть 5 или 7.

Custom_Nova_Launcher-088Custom_Nova_Launcher-087

Android_для_чайников_1-7Android_для_чайников_1-5

В нижней части экрана находятся иконки док-бара, которые всегда видны на любом рабочем столе. Обычно там находятся иконки адресной книги, браузера, программы для работы с SMS. Центральная иконка — вызов меню со списком всех установленных программ.

Строка состояния

В самом верху экрана расположена строка состояния. Именно там отображаются текущее время, заряд аккумулятора и активные уведомления. Строку состояния можно раскрывать, для этого достаточно провести пальцем от верхнего края экрана вниз. В раскрытом виде строку состояния часто называют «шторкой».

Если в самой строке состояния отображаются только небольшие иконки уведомлений, то в «шторке» панели уведомлений можно получить о них всю необходимую информацию. Например, вы не просто видите, что пришло новое SMS, но сразу понимаете, когда и от кого. Удалить лишние уведомления очень легко — достаточно просто «смахнуть» их с экрана с помощью горизонтального свайпа.

Android_для_чайников_1-30Android_для_чайников_1-29

Как вы могли заметить, последнее пришедшее уведомление, которое расположено в самом верху «шторки», занимает заметно больше места, чем остальные. Сделано это не просто так — последнее событие считается наиболее актуальным и важным для пользователя, поэтому о нем показана дополнительная информация, что очень удобно. К примеру, если это письмо или SMS, то вам хватит одного беглого взгляда, чтобы оценить, насколько оно для вас важно. Более того, в большинстве случаев вы сможете на него ответить буквально в один клик, даже не закрывая «шторку» панели уведомлений.

Android_для_чайников_1-3Android_для_чайников_1-4

Помимо уведомлений, из строки состояния можно получить доступ ко всем основным переключателям. С их помощью можно включить или отключить Wi-Fi или мобильный интернет, отрегулировать яркость экрана, перевести смартфон в беззвучный режим и прочее. Конкретный набор функций и способ переключения с панели уведомлений на панель переключателей на разных смартфонах заметно разнится. Где-то для этого используется вертикальный свайп, где-то — нажатие на иконку в правом верхнем углу экрана.

Обои, виджеты, иконки

Но давайте вернемся к рабочему столу. Как я уже говорил, в Android их может быть несколько, и сделано это не просто так. Ведь на рабочем столе могут находиться не только иконки приложений, которые занимают не так уж много места, но и объемные виджеты.

TOP-60_HD_Виджеты-03TOP-60_HD_Виджеты-04

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

Android_для_чайников_1-8Android_для_чайников_1-6

Долгое время виджеты были отличительной чертой Android. За время существования этой ОС были созданы тысячи разнообразных виджетов всех цветов и размеров. Большинство из них способно работать на любой прошивке или фирменной оболочке, но есть и такие, которые установить на «не родные» смартфоны нельзя.

Кроме того, не стоит забывать и об эстетической стороне вопроса. Не всем нравится, когда рабочий стол полностью загроможден виджетами и иконками, которые не дают рассмотреть красивые обои. В Android это не проблема — создайте дополнительный рабочий стол и перенесите мешающие вам иконки туда. Для этого нужно выполнить по иконке долгий тап, а затем перетащить к краю экрана, «перелистнув» его на нужный рабочий стол.

Android_для_чайников_1-1Android_для_чайников_1-2

Изменить обои или вынести на рабочий стол новый виджет можно через режим редактирования рабочих столов. Активируется на разных смартфонах он немного по-разному. В основном требуется либо сделать на пустом месте экрана долгий тап, либо выполнить «щипок» по любому рабочему столу. Иконки приложений вынести на рабочий стол еще проще — достаточно просто зайти в меню приложений и выполнить долгий тап по нужному значку.

Android_для_чайников_1-06Android_для_чайников_1-05

Android_для_чайников_1-04Android_для_чайников_1-03

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

Custom_One_banner

Custom_Two_banner

Здесь же я остановлюсь только на установке своей мелодии на звонок. Дело в том, что в Android смартфонах этот момент очень часто реализован не очень понятно и вызывает у новых пользователей вопросы.

Установка мелодии вызова

Для начала рассмотрим классический способ установки мелодии вызова – через меню настроек. Заходим в настройки телефона, переходим в раздел «Звук» и выбираем пункт «Мелодия звонка».

Чайник_19-04Чайник_19-03

Перед нами список стандартных мелодий, заранее установленных в смартфон производителем. На некоторых аппаратах прямо из этого же меню можно выбрать свою собственную композицию. Например, на смартфоне HTC One (M8), который используется в этой статье в качестве примера, для этого служит иконка «+», расположенная в верхнем правом углу экрана.

Чайник_19-02Чайник_19-01

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

Для этого нужно подключить смартфон к компьютеру с помощью кабеля, нажать на компьютере кнопку «Пуск», выбрать пункт «Мой компьютер» и в открывшейся папке найти значок вашего смартфона. Именно его нам и нужно открыть. Скорее всего, выглядеть он будет вот так, а его название будет совпадать с названием модели телефона. На некоторых смартфонах для передачи данных необходимо разблокировать экран (актуально в том случае, если вы установили пароль на разблокировку).

Чайник_17-19

Нас интересует папка «Media». Внутри нее должна находиться папка «Audio», а в ней, в свою очередь, папка «Ringtones». Таким образом, полный путь до интересующей нас папки выглядит следующим образом: MediaAudioRingtones. Именно сюда и следует скопировать нужную вам мелодию. Если таких папок во внутренней памяти смартфона нет, то их необходимо создать. Главное — сделать это именно в том порядке, как указано выше.

Для верности стоит перезагрузить смартфон. Все, теперь выбранная вами мелодия появится в общем списке. Схожим образом можно установить мелодию на звонок будильника, только путь в этом случае будет немного другой: MediaAudioAlarms.

Если возиться с подключением смартфона к компьютеру не хочется, можно сделать проще. Открыть нужную вам мелодию в аудиоплеере, а затем выбрать пункт «Установить на звонок» во всплывающем меню.

Custom_One-82Custom_One-81

В старых версиях Android был неприятный «глюк», из-за которого назначенная таким образом мелодия «слетала» после перезагрузки смартфона. Но на современных телефонах я ничего подобного не встречал.

Способ установки персональной мелодии немного отличается на разных моделях смартфонов, но ничего сложного тут в любом случае нет. Для начала откройте телефонную книгу и тапните пальцем по нужному контакту. Среди прочей информации найдите пункт «Мелодия звонка», «Мелодия вызова» или «Установка рингтона».

Чайник_19-05Чайник_19-06

Если ничего подобного на экране нет, то нажмите на кнопку «Меню» — скорее всего, нужный нам пункт находится там.

Часть третья. Установка приложений

Чем смартфон отличается от простенькой «звонилки»? В первую очередь, многозадачностью и поддержкой огромного числа разнообразных приложений. Это клиенты социальных сетей и приложения для видеозвонков, программы для работы с корпоративной почтой и офисные пакеты, мобильные версии знаменитых программ Adobe и видеоредакторы, спортивные тренеры и автомобильные навигаторы, программы для чтения книг и просмотра фильмов, потрясающие 3D игры и приложения-фотокамеры с разными фильтрами… миллионы программ на любой вкус и цвет.

Запутаться в таком многообразии было бы очень легко, если бы не официальный магазин приложений Google Play. Благодаря удобным категориям, прозрачной рейтинговой системе, тысячам отзывов от пользователей, подборкам и рекомендациям, найти для себя подходящую программу сможет даже самый неопытный пользователь.

Google Play

Прежде всего, еще раз напомню, что для доступа к Google Play вам нужен аккаунт Google. Информация о нем была в начале статьи. Значок самого магазина всегда находится на центральном рабочем столе смартфона — это одно из требований Google, которому вынуждены следовать все производители. Если вы его случайно удалили, то не беда — просто зайдите в меню приложений (обычно это центральная клавиша в док-баре) и запустите его оттуда.

Android_для_чайников_1-02Android_для_чайников_1-01

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

Android_для_чайников_1-14Android_для_чайников_1-13

Нас, в первую очередь, интересуют разделы игр и программ. Прежде всего, стоит отметить, что приложения бывают как платные, так и бесплатные. С приобретением бесплатных приложений все понятно — достаточно нажать на кнопку «Загрузить», а затем проверить список разрешений, которые требуются приложению для работы. Что же касается приложений платных, то вначале вам предложат выбрать способ оплаты. Это либо кредитная карта, либо счет вашего мобильного телефона. Правда, последнюю возможность пока поддерживают не все операторы мобильной связи, но тут уж ничего не поделаешь.

Android_для_чайников_1-08Android_для_чайников_1-07

Разделы программ и игр состоят из нескольких экранов, переключение между которым осуществляется с помощью горизонтального свайпа. На главном экране отображаются рекомендации друзей и советы редакции Google Play. Левый экран отведен под список категорий, с помощью которых можно быстро попасть в нужный подраздел.

Android_для_чайников_1-12Android_для_чайников_1-11

Справа от главного экрана расположены экраны со списками самых популярных платных и бесплатных приложений. Если не знаете, что именно установить на свой новый смартфон, обязательно загляните туда.

Android_для_чайников_1-10Android_для_чайников_1-09

К сожалению, популярность — штука непостоянная. Да и накрутить рейтинг, в теории, тоже вполне возможно. И иногда в «Топ» попадают какие-то уже совсем странные приложения, которые представляют интерес только для очень узкой аудитории. А вот проверенные временем программы, которые и так установили себе уже практически все, из «Топа» иногда пропадают, ведь количество их новых загрузок не так уж велико.

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

Защита от случайных покупок

Есть у Google Play и еще один минус. Вернее, даже не столько у самого Google Play, сколько у современных игр и приложений, распространяемых по схеме Free-to-Play. В подавляющем большинстве в них есть система внутриигровых покупок, которая может стать очень неприятным сюрпризом.

Очень многие родители время от времени дают детям поиграть в игры на своем смартфоне. И, разумеется, никакого подвоха в этот момент они совершенно не ожидают. В самом деле, ну что может натворить маленький ребенок во время игры в какого-нибудь «Крокодильчика Свомпи», Cut The Rope или Angry Birds? Тем более, сидя рядом с родителями?

К сожалению, многие недооценивают ту скорость, с которой современные дети разбираются с новой техникой. Быстро освоив управление и пройдя пару уровней, малыш может заинтересоваться красочными иконками, предлагающими открыть доступ к новым сказочным героям или красивым предметам. Увы, не бесплатно – но этого-то как раз маленький ребенок может и не понять. И досадное всплывающее окошко с подробностями оплаты и единственной большой кнопкой его не остановит – куда нужно нажимать в таких случаях, дети отлично знают.

Чайник_11-03Чайник_11-02

Отдельно отмечу, что тот факт, что игра находится в разделе «Бесплатные игры», вовсе не гарантирует отсутствие в ней внутриигровых покупок. Скорее даже наоборот – создатели большинства бесплатных игр обожают навязывать пользователям разнообразный платный контент. Это и покупка внутриигровой валюты, и особые предметы, и специальные бонусы, и новые герои, и доступ к секретным миссиям… В некоторых играх приходится платить даже за то, чтобы просто пройти несколько уровней подряд. И обо всех этих возможностях вам будут постоянно напоминать во время игры, используя красочные баннеры и заботливые всплывающие подсказки. Тут не то что ребенку, тут и многим взрослым бывает сложно устоять. Неудивительно, что современные «бесплатные» игры обычно приносят своим создателям во много раз больший доход, чем игры изначально платные.

Отличить «условно-бесплатные» игры от «полностью бесплатных» очень легко. Если игра предусматривает возможность внутриигровых покупок, то об этом будет явным образом указано на ее странице в Google Play. Соответствующая надпись располагается рядом с кнопкой «Установить». Аналогичное разрешение потребуется игре во время установки.

Чайник_11-04Чайник_11-01

Чтобы раз и навсегда решить проблему случайных покупок, следует установить на них пароль. Сделать это очень легко. В первую очередь, нужно открыть магазин приложений Google Play. Обычно его иконка расположена прямо на главном экране смартфона.

Затем – открыть боковое меню. Сделать это можно, нажав на иконку в левом верхнем углу экрана либо просто проведя пальцем от левой кромки экрана вправо.

Чайник_11-08Чайник_11-07

Теперь остается только перейти в раздел настроек и нажать на строку «Запрашивать пароль при покупке». На большинстве устройств по умолчанию используется вариант «Запрашивать каждые 30 минут». В этом случае вводить пароль потребуется только один раз в полчаса, а все остальные покупки в этом интервале можно будет совершать без дополнительного подтверждения.

Чайник_11-06Чайник_11-05

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

Скидки и распродажи

Впрочем, в Google Play хватает и приятных сюрпризов. А именно скидок, бонусов и распродаж. Хотя цены в магазине Google обычно не слишком большие, возможность сэкономить всегда приятна.

Многие пользователи Android устройств даже не подозревают, что скидки на те или иные программы появляются в Google Play практически ежедневно. Иногда речь идет о символических 10-20% скидки, но иногда скидка составляет 90%, а то и все 100%. Проблема только в том, что вручную следить за изменением цен ассортимента магазина Google практически невозможно — уж больно много в нем разных программ.

Но этому горю несложно помочь. Достаточно просто установить специальное приложение, которое будет сообщать вам о текущих скидках и распродажах. Программ такого типа довольно много. В качестве примера приведу приложение AppSales, о котором уже как-то упоминалось на этом сайте.

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

Чайник_25-10Чайник_25-09

На главном экране показаны текущие скидки. Как видите, они весьма солидные. Причем зачастую речь идет о весьма известных программах. Например, на скриншоте вы можете заметить 80% скидку на популярную игру компании Ubisoft.

Чайник_25-08Чайник_25-07

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

Кликнув на название приложения можно просмотреть о нем подробную информацию. Его описание, системные требования, график изменения цены. А если вы ждете скидки на какую-то конкретную программу, то можно просто добавить ее в список отслеживаемых.

Чайник_25-06Чайник_25-05

Выбор программ по умолчанию

Как вы могли заметить, Android дает пользователю возможность буквально «в пару кликов» заменить любую предустановленную программу или системный компонент. Хотите попробовать другой браузер? А может быть, установить новую клавиатуру? Или, к примеру, заменить стандартный почтовый клиент или календарь? Нет ничего проще.

Но что произойдет, если на смартфоне окажется сразу несколько программ для одной и той же цели? Например, какой браузер откроется при клике по ссылке в письме, если помимо стандартного браузера, на смартфоне установлена еще и Opera mini? Или какой именно проигрыватель запустится при клике на видеофайл?

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

Чайник_7-02Чайник_7-01

Как видите, можно как выбирать программу каждый раз вручную, так и попросить смартфон запомнить выбор и больше не показывать это диалоговое окно.

Конечно, второй вариант удобнее, и большинство владельцев Android смартфонов предпочитают пользоваться именно им. Но иногда случается так, что во время выбора пользователь случайно кликает не на то приложение, или же просто спустя какое-то время хочет вернуть старый вариант. Для этого достаточно открыть настройки смартфона, зайти в раздел «Приложения», найти в нем выбранную программу и нажать на кнопку «Удалить настройки по умолчанию» либо «Очистить значения по умолчанию». Это позволит снова вернуть уже знакомое нам диалоговое окно с выбором программы.

Чайник_7-06Чайник_7-05

Чайник_7-04Чайник_7-03

Обратите внимание, что в некоторых оболочках раздел «Приложения» разбит на несколько вкладок: «Сторонние», «На карте SD», «Запущенные» и пр. В этом случае во избежание путаницы лучше сразу переключиться на вкладку «Все приложения».

Как видите, ничего сложного в выборе программ по умолчанию нет. Поэтому не бойтесь экспериментировать и пробовать новые программы. В Google Play есть масса достойных приложений, которые могут понравиться вам намного больше тех, что предустановлены в вашем телефоне изначально.

Удаление программ

Итак, с установкой программ мы более-менее разобрались. Самое время поговорить про их удаление.

Прежде всего, стоит отметить, что на многих смартфонах удаление приложения происходит буквально «в один клик». Для этого нужно просто открыть меню приложений, «подцепить» пальцем значок программы и перетащить его в верхнюю часть экрана, где появится иконка корзины. Хотя в «чистом» Android такой возможности нет, многие производители смартфонов добавляют ее в своих фирменные оболочки.

Не получилось удалить приложение таким образом? Не беда! Есть универсальный способ, который подходит для любого Android смартфона.

Принцип тут примерно тот же, что и в настольной Windows. Нужно открыть меню настроек и выбрать в нем пункт «Приложения». Обычно это окно разделено на несколько вкладок, переключиться между которыми можно с помощью горизонтального свайпа. Удобнее всего пользоваться вкладкой «Сторонние приложения», но если нужного вам приложения там по какой-то причине нет, то можно переключиться на вкладку «Все».

Чайник_2-15Чайник_14-08

Чайник_14-07Чайник_14-06

Теперь остается только найти в списке то самое приложение, от которого вы хотите избавится, а затем нажать на кнопку «Удалить». Обратите внимание, что если вы хотите сбросить настройки приложения на «заводские» или очистить его данные, то переустанавливать само приложение вовсе не обязательно. Достаточно воспользоваться кнопкой «Удалить данные» или «Очистить данные», которая находится чуть ниже на этом же экране.

Чайник_14-05Чайник_14-10

Второй способ удалить установленную программу – воспользоваться магазином Google Play. Прежде всего, нужно открыть сам Google Play, нажав на соответствующую иконку на рабочем столе или в меню приложений. Затем нажать на значок меню (иконка из трех полосок в левом верхнем углу) либо выполнить горизонтальный свайп от левой кромки экрана. В открывшемся меню нужно выбрать пункт «Мои приложения», дотронуться до названия нужной программы и нажать на кнопку «Удалить».

Чайник_14-04Чайник_14-03

Чайник_14-02Чайник_14-01

Как видите, ничего сложного в удалении приложений нет. Единственный немного неприятный момент — удалить таким образом можно только сторонние приложения, которые вы сами скачали из Google Play после покупки смартфона. А вот избавиться от тех программ, которые производитель установил на ваш смартфон изначально, к сожалению, так просто не получится.

Установка приложений из сторонних источников

Разработчики Android с самого начала предполагали, что для поиска и установки приложений пользователями будет использоваться магазин Google Play. В том числе и из соображений безопасности – программе с вредоносным кодом попасть в этот магазин приложений практически невозможно.

Тем не менее, в Android предусмотрена возможность установки приложений, вручную скачанных со сторонних сайтов. Другое дело, что по умолчанию она заблокирована.

Включить установку приложений из сторонних источников можно в настройках телефона. Обычно нужный нам пункт находится в разделе «Безопасность».

Чайник_21-04Чайник_21-03

Затем остается только скачать на телефон установочный файл, имеющий расширение .*apk, запустить его и внимательно проверить, какие разрешения он запрашивает. Последний пункт очень важен, и отнестись к нему нужно максимально ответственно.

Чайник_21-02Чайник_21-01

Как видите, установить приложение с какого-то стороннего сайта совсем не сложно. Но неопытным пользователям пользоваться таким способом я категорически не рекомендую. Подавляющее большинство «бесплатных» версий платных программ, которые предлагают вам скачать авторы красочных баннеров — самые настоящие вирусы, которые за считанные минуты опустошат счет вашего телефона. Чудес на свете не бывает, и польстившись на предложение «обновить телефон до Android 5.0», «скачать Flash Player» или «выиграть миллион», вы практически гарантировано заражаете свой смартфон какой-то гадостью.

Заразить Android смартфон вирусом вы можете только собственноручно, ведь эта ОС устроена таким образом, что любая программа поневоле предупреждает вас о том, какими именно правами она хочет обладать. И пока вы не нажмете на кнопку «Ок», доступ к вашему смартфону не получит. Именно поэтому создатели вирусов всеми правдами и неправдами попытаются убедить вас, что их приложение совершенно безобидно, а права на отправку платных SMS ему нужны просто так.

Любое приложение, которое вы скачиваете не из официального магазина — потенциальный риск, который может обойтись вам очень и очень дорого. Разрешая установку приложений из сторонних источников, вы лишаете себя самого простого и надежного способа защиты.

Сторонние магазины приложений

Если уж магазин Google Play оказался чем-то не мил, то лучше поступить иначе. Ведь многие известные компании, от Яндекс до Amazon, имеют свои магазины приложений, во многом похожие на Google Play. И воспользоваться ими может любой желающий.

Главный вопрос тут звучит даже не «как», а «зачем». Что в этих магазинах есть такого, чего не может предложить Google Play?

На самом деле, ответ на этот вопрос совсем не очевиден. Ассортимент приложений у них в любом случае будет меньше. Да и по немногочисленным отзывам и оценкам далеко не всегда можно понять, стоит ли та или иная программа запрашиваемых денег. А какие-то эксклюзивные предложения бывают скорее в теории, чем на практике – редкий разработчик предпочтет променять огромнейшую аудиторию Google Play на сомнительные бонусы местного магазина.

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

Рассмотрим установку стороннего магазина на примере Yandex Store. Прежде всего нужно убедиться, что в настройках смартфона разрешена установка приложений из сторонних источников. Об этом мы говорили чуть выше. Затем – скачать клиент магазина. Для этого нужно открыть с мобильного телефона адрес m.ya.ru/ystore. Обязательно убедитесь, что вы скачиваете файл именно с официального сайта, а не из каких-то файлообменников и прочих сомнительных источников.

Чайник_30-22Чайник_30-21

Чайник_30-20Чайник_30-19

Третий шаг – установка приложения. Тут все стандартно – проверяем требуемые программой разрешения, пару раз нажимаем «Далее» и в самом конце – «Принять».

Чайник_30-18Чайник_30-17

Чайник_30-16Чайник_30-15

Внешне магазин напоминает немного упрощенную копию Google Play. Основной экран разбит на три вкладки («Интересное», «Игры», «Приложения), в самом верху находятся иконки поиска и настроек. Рядом с иконкой поиска вы можете заметить оранжевый квадратик индикатора обновлений. Интересный момент –Yandex Store может обновлять даже те приложения, которые вы скачали через Google Play. Разумеется, в том случае, если в нем они также присутствуют.

Чайник_30-14Чайник_30-13

Чайник_30-12Чайник_30-11

Чайник_30-10Чайник_30-09

Чайник_30-08Чайник_30-07

Для покупки приложений нужно указать магазину желаемый способ оплаты. А пред этим – зарегистрироваться либо войти под уже имеющимся Яндекс логином.

Чайник_30-06Чайник_30-05

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

Чайник_30-04Чайник_30-03

Чайник_30-02Чайник_30-01

Если вы решите установить какие-то иные сторонние магазины, то уделите особое внимание трем вещам:

  • Скачивайте клиент магазина только из надежных источников. Не верьте уловкам мошенников, предлагающих вам «особую» версию магазина с «бесплатными» играми и программами.
  • Перед тем, как что-то покупать, убедитесь, что вы можете скачать и установить из этого магазина какое-либо бесплатное приложение. Некоторые магазины могут требовать дополнительной регистрации, работать не во всех странах и прочее.
  • Помните, что правила Google Play в других магазинах не действуют. В первую очередь это касается политики возврата средств.

Android_min

Продолжение следует…


Понравилась статья? Поделить с друзьями:
  • Монурал цена в ростове на дону инструкция по применению
  • Часы skmei 1427 инструкция на русском
  • Амоксиклав инструкция по применению таблетки детям 500 мг цена
  • Газпром экспорт официальный сайт руководство
  • Фезам 400 25 инструкция по применению цена отзывы