Как создать бэкэнд для приложения под Android?
В этой статье мы поговорим об Android – одной из самых популярных операционных систем. Мы рассмотрим плюсы и минусы разработки под Android, варианты бэкенда для мобильных приложений и научим вас создавать свой собственный мобильный бэкенд.
Contents
- 1 Основные выводы
- 2 Что такое Android?
- 3 Преимущества разработки под Android
- 4 Ограничения разработки под Android
- 5 Варианты бэкенда для приложений Android
- 6 Как сделать бэкэнд для приложения под Android?
- 7 Заключение
Основные выводы
- Доминирование Android: На Android, как на ОС с открытым исходным кодом, работает около 70% мобильных устройств с более чем тремя миллиардами активных пользователей.
- Варианты бэкенда для приложений: В качестве бэкенда для мобильных приложений разработчики могут выбрать инфраструктуру как услугу (IaaS), платформу как услугу (PaaS) или бэкенд как услугу (BaaS).
- Шаги по созданию бэкенда: В конце статьи мы предоставим подробное руководство по созданию бэкенда для Android с использованием платформы BaaS и исходный код.
Что такое Android?
Android – это бесплатная операционная система с открытым исходным кодом на базе Linux. Она была разработана в первую очередь для мобильных устройств, таких как смартфоны и планшеты, но теперь также используется для умных телевизоров, встраиваемых систем, игровых консолей и так далее.
Разработка Android началась в 2003 году компанией Android Inc. Изначально компания хотела создать ОС для цифровых камер, но быстро переключилась на разработку мобильных ОС, чтобы выйти на более широкий рынок.
В 2005 году компания была приобретена Google вместе со своими сотрудниками. Первая версия Android была выпущена в 2008 году.
Несмотря на то что Android имеет открытый исходный код, большинство мобильных устройств работают под управлением собственной версии Google. В их версии предустановлены такие программы, как Google Chrome, YouTube, Google TV и Gmail.
Благодаря широким возможностям кастомизации Android многие производители также настраивают Android, чтобы лучше представить свою компанию. Именно поэтому OnePlus Android выглядит совсем иначе, чем Pixel Android.
Android является самой популярной операционной системой с 2013 года. Она используется примерно на 70 % мобильных устройств и насчитывает более трех миллиардов ежемесячных активных пользователей.
Кроме того, Google Play Store предоставляет вам доступ к более чем трем миллионам мобильных приложений. Продолжайте читать, чтобы узнать, как создать бэкэнд для приложения для Android.
Преимущества разработки под Android
Давайте рассмотрим некоторые преимущества разработки под Android.
Кросс-платформа
Разработка под Android позволяет охватить широкий спектр устройств. Это и мобильные телефоны, и носимые устройства, и “умные” телевизоры, и игровые консоли, и многое другое. Если вы знаете, как создавать мобильные приложения, вам не составит труда разработать приложение для носимых устройств или смарт-телевизоров.
Огромный рынок
Как уже говорилось ранее, Android занимает большую долю рынка – 70%, по сравнению с iOS – 30%. Разрабатывая приложения для Android, вы автоматически получаете доступ к более широкой аудитории.
Кроме того, приложения для Android известны своими низкими инвестициями и высокой окупаемостью. В отличие от iOS, здесь также нет ежегодной платы за услуги разработчика.
Настраиваемость
По сравнению с другими операционными системами устройства Android отличаются высокой степенью настраиваемости. Они позволяют изменить практически все, что только можно себе представить.
Кроме того, Android позволяет легко интегрировать ваше приложение с другими сторонними сервисами.
Сообщество
Android поддерживается огромным сообществом разработчиков с открытым исходным кодом. Более того, он поставляется с множеством удобных для разработчиков инструментов, таких как Android Studio, ADB и Logcat, которые позволяют легко создавать приложения.
Если вы вдруг застрянете, есть несколько платформ, где вы можете найти помощь, включая GitHub, StackOverflow, Reddit и другие сообщества, ориентированные на Android.
Ограничения разработки под Android
Вот некоторые минусы разработки под Android.
Безопасность
Android менее защищен, чем iOS, и не придерживается строгих протоколов безопасности. Поскольку Android имеет открытый исходный код, уязвимости в системе безопасности обнаруживаются еженедельно. Это дает хакерам возможность использовать эти уязвимости до того, как они будут исправлены.
Устройства Android также можно рутировать, чтобы получить доступ суперпользователя. Хотя это делает устройство более мощным, это также рискованно, поскольку отключает некоторые встроенные меры безопасности.
Сложность
Устройства Android бывают разных форм и размеров, и хотя это здорово, это может стать огромным недостатком при разработке приложений для Android для нескольких типов устройств.
Чтобы ваше приложение было совместимо с максимальным количеством устройств, вам придется внедрить отзывчивый дизайн, продумать аппаратную часть различных устройств и т. д.
Премиальные приложения
Премиум-приложения пользуются меньшим успехом в Google Play Store по сравнению с App Store. Не секрет, что пользователи Android обычно тратят на приложения меньше, чем пользователи iOS. Если вы работаете над приложением премиум-класса, считайте Android вторым выбором.
Варианты бэкенда для приложений Android
Какой бэкенд лучше всего подходит для приложений Android? Бэкенды для мобильных приложений могут быть размещены на собственной инфраструктуре или развернуты в облачных сервисах. Наиболее популярные модели облачных вычислений для мобильных бэкендов включают:
- Инфраструктура как услуга (IaaS)
- Платформа как услуга (PaaS)
- Бэкэнд как услуга (BaaS)
Каждый вариант охватывает различные уровни абстракции, как показано на рисунке ниже.
Давайте подробно рассмотрим каждый вариант, чтобы помочь вам выбрать наиболее подходящую облачную модель для ваших внутренних приложений.
Инфраструктура как услуга (IaaS)
Инфраструктура как услуга (IaaS) – это наименее абстрактная модель облачных вычислений. В этой модели поставщик предлагает пользователям виртуализированные ресурсы, такие как серверы, сети, хранилища и операционные системы, через высокоуровневые API или интуитивно понятные панели управления.
Самое лучшее в IaaS – это то, что он дает пользователям полный контроль над всей инфраструктурой. IaaS – самая гибкая и масштабируемая модель, но и самая сложная в управлении. Если вы выберете этот вариант, вам, скорее всего, понадобится системный администратор или два.
Примерами IaaS являются Amazon Web Services, Google Cloud Platform и Azure.
Платформа как услуга (PaaS)
Платформа как услуга (PaaS) – это модель облачных вычислений, призванная помочь пользователям в разработке, управлении и развертывании приложений.
Помимо предоставления инфраструктуры, PaaS поставляется с удобными инструментами для разработки, настройки и тестирования приложений.
Используя PaaS, вы сможете сосредоточиться на своем программном обеспечении и пользовательском опыте, не заботясь о базовой инфраструктуре.
Кроме того, PaaS обеспечит масштабирование вашего приложения по требованию, позаботится о резервном копировании и так далее. Недостатками PaaS являются более низкий уровень контроля, риск блокировки поставщика и сравнительно более высокая стоимость.
Самые популярные PaaS-платформы – Heroku, Render и Digital Ocean App Platform.
Бэкэнд как услуга (BaaS)
Бэкенд как услуга (BaaS) автоматизирует внутреннюю часть разработки, предоставляя полноценное бэкенд-решение.
Функции BaaS включают управление пользователями, базы данных, аутентификацию, социальные интеграции, push-уведомления, API, SDK и многое другое.
BaaS дает вам все преимущества IaaS и PaaS, предоставляя при этом дополнительные функциональные возможности. Команды, использующие BaaS, как правило, быстрее выпускают свои продукты, сокращают затраты на проектирование и создают более качественное программное обеспечение.
К недостаткам BaaS можно отнести более низкий уровень контроля и кастомизации, а также возможность блокировки поставщика для платформ без открытого исходного кода.
Примеры BaaS включают Back4app, AWS Amplify и Firebase.
Как сделать бэкэнд для приложения под Android?
В этом разделе статьи мы рассмотрим, как создать внутреннее приложение на базе Back4app и подключиться к нему из Android-приложения.
Пререквизиты
- Опыт работы с Kotlin и разработки под Android.
- Базовое понимание мобильного бэкенда как сервиса.
- На локальном компьютере установлены Java и Android Studio.
Что такое Back4app?
Back4app – это отличная платформа для создания бэкендов современных приложений и ускорения процесса разработки.
Он оснащен такими полезными функциями на стороне сервера, как управление пользователями, базы данных в реальном времени, социальные интеграции, функции Cloud Code, push-уведомления, API и многое другое!
Используя Back4app, вы сможете передать на сторону большую часть работы по созданию бэкенда и сосредоточиться на критически важных аспектах вашего приложения, а также ускорить разработку бэкенда приложения для Android.
Вам не нужно будет заниматься базовой инфраструктурой, сервером бэкенда, масштабированием, обслуживанием и т. д.
Самое главное, что Back4app предлагает бесплатный уровень, который отлично подходит для экспериментов и тестирования платформы. По мере роста вашего приложения вы можете перейти на премиум-планы за ежемесячную плату.
Введение в проект
В этой статье мы создадим простое приложение для заметок. Приложение позволит пользователям добавлять, редактировать и удалять заметки. Заметки будут храниться в базе данных Back4app и управляться с помощью Parse SDK.
Для создания приложения мы будем использовать язык программирования Kotlin. Для создания пользовательского интерфейса мы будем использовать Jetpack Compose – современный инструментарий Android для создания нативных пользовательских интерфейсов.
Создать приложение Back4app
В качестве первого шага для разработки бэкенда для приложения Android вам понадобится учетная запись Back4app. Если у вас его нет, зарегистрируйтесь.
Когда вы войдете в свою учетную запись Back4app, вы будете перенаправлены в раздел приложений. Нажмите “Создать новое приложение”, чтобы начать процесс создания приложения.
Платформа Back4app предлагает два решения:
- Бэкенд как услуга (BaaS) – надежное решение для бэкенда
- Containers as a Service (CaaS) – платформа для управления контейнерами (в частности, веб-приложениями)
Учитывая, что мы создаем бэкенд для мобильного приложения, мы будем использовать “бэкенд как сервис”.
Дайте своему приложению красивое и информативное название, выберите “NoSQL” в качестве базы данных и нажмите “Создать”. Это важный шаг для развертывания бэкенда для приложения Android.
Back4app потребуется некоторое время, чтобы подготовить все необходимое для вашего приложения. Это включает в себя базу данных, управление пользователями, масштабирование, конфигурации и так далее. Как только приложение будет готово, вы будете перенаправлены к представлению базы данных вашего приложения.
Разработка базы данных
Двигаясь дальше, давайте спроектируем базу данных. Это необходимый шаг для разработки бэкенда приложения для Android.
Поскольку мы создаем простое приложение для заметок, нам понадобится только один класс. Нажмите “Создать класс”, назовите его Note
, включите “Public Read and Write” и нажмите “Create class & add columns”.
Затем добавьте следующие три поля в только что созданный класс:
+-------------+-------------+--------------------+----------+
| Data type | Name | Default value | Required |
+-------------+-------------+--------------------+----------+
| String | icon | <leave blank> | yes |
+-------------+-------------+--------------------+----------+
| String | title | <leave blank> | yes |
+-------------+-------------+--------------------+----------+
| String | content | <leave blank> | yes |
+-------------+-------------+--------------------+----------+
Наконец, нажмите на кнопку “Добавить строку” и заполните базу данных образцами данных. Если у вас нет никаких идей, вы также можете импортировать этот дамп данных.
Отлично, это все для бэкэнда.
Код Frontend
В этом разделе статьи мы загрузим новое приложение для Android, настроим ViewModel, реализуем пользовательский интерфейс, установим и настроим Parse SDK и, наконец, получим данные из базы данных Back4app в режиме реального времени.
Проект “Инит
Как уже говорилось в разделе “Предварительные условия”, для выполнения следующих шагов вам потребуется установить Android Studio. Если у вас ее еще нет, скачайте ее.
Начните с открытия Android Studio и нажмите кнопку “Новый проект”.
Затем выберите “Empty Activity” в качестве шаблона проекта и нажмите “Next”.
Чтобы создать проект, необходимо указать имя и название пакета. Я предлагаю вам использовать AndroidApp
в качестве имени проекта и обратное доменное имя в качестве пакета проекта.
После того как вы все настроили, нажмите “Finish”, чтобы создать проект.
Android Studio потребуется около двух минут, чтобы подготовить все необходимое. Сюда входит создание файловой структуры проекта, настройка Gradle, установка зависимостей и т. д.
Когда ваш проект будет готов, с помощью проводника перейдите к файлу MainActivity.kt и замените его содержимое:
// app/src/main/java.<your_package_name>/MainActivity.kt
package <your.package.name>
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.sp
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MaterialTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background,
) {
Text(text = "Back4app rocks!", fontSize = 18.sp)
}
}
}
}
}
Обязательно замените на фактическое имя пакета.
И наконец, попробуйте запустить приложение, нажав на зеленую кнопку воспроизведения или Shift + F10
на клавиатуре. Если все прошло успешно, эмулятор должен запуститься, и вы увидите на экране сообщение Back4app rocks
.
ViewModel
Для управления глобальным состоянием нашего приложения мы будем использовать ViewModel
. Но перед этим нам нужно создать класс данных Note
с теми же атрибутами, что и в нашей базе данных Back4app.
Создайте класс данных с именем Note
:
// app/src/main/java.<your_package_name>/Note.kt
package <your.package.name>
data class Note(
var objectId: String? = null,
var icon: String,
var title: String,
var content: String,
) {
companion object {
fun generateObjectId(): String {
val chars = ('a'..'z') + ('A'..'Z') + ('0'..'9')
return (1..10).map { chars.random() }.joinToString("")
}
}
}
- Мы определили статический метод
generateObjectId()
для генерации Parse-подобных идентификаторов объектов. objectId
может быть нулевым, поскольку в дальнейшем мы будем считать, что еслиobjectId == null
, то объект еще не был сохранен в базе данных.
Затем создайте класс AppViewModel
со следующим содержимым:
// app/src/main/java.<your_package_name>/AppViewModel.kt
package <your.package.name>
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
class AppViewModel : ViewModel() {
val notes: MutableState<Map<String, Note>> = mutableStateOf(mapOf(
"7IggsqFAKt" to Note(
objectId = "7IggsqFAKt",
icon = "\uD83D\uDE80",
title = "Deploy app",
content = "Go ahead and deploy your backend to Back4app.",
),
"eFRNm0hTat" to Note(
objectId = "eFRNm0hTat",
icon = "\uD83C\uDFA8",
title = "Design website",
content = "Design the website for the conference.",
),
"uC7hTQmG5F" to Note(
objectId = "uC7hTQmG5F",
icon = "\uD83D\uDC42",
title = "Attend meeting",
content = "Attend meeting with the team to discuss the conference.",
),
))
companion object {
@Volatile
private var instance: AppViewModel? = null
fun getInstance(): AppViewModel {
return instance ?: synchronized(this) {
instance ?: AppViewModel().also { instance = it }
}
}
}
}
- Мы использовали
MutableState
в Compose для запуска обновления пользовательского интерфейса в случае изменения данных. MutableState
содержиткарту
объектов (ObjectIds
) изаметок (Notes)
, которые мы заполнили данными.- Чтобы гарантировать, что существует только один экземпляр
AppViewModel
, мы использовали паттерн singleton.
Теперь мы можем получить доступ к экземпляру AppViewModel
в нашей деятельности через AppViewModel.getInstance().
Основная деятельность
Двигаясь дальше, замените содержимое файла MainActivity.kt следующим кодом для отображения заметок:
// app/src/main/java.<your_package_name>/MainActivity.kt
package <your.package.name>
import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material3.ExtendedFloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
class MainActivity : ComponentActivity() {
private val viewModel = AppViewModel.getInstance()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val context = this as Context
setContent {
MainActivityContent(
viewModel = viewModel,
onNoteListItemClick = {
// TODO: Open note edit form
},
onNoteAddClick = {
// TODO: Open note create form
},
)
}
}
}
@Composable
fun MainActivityContent(
viewModel: AppViewModel,
onNoteListItemClick: (note: Note) -> Unit,
onNoteAddClick: () -> Unit,
) {
val notes = viewModel.notes.value
MaterialTheme {
Scaffold(
topBar = { TopAppBar(title = { Text("My Notes") }) },
floatingActionButton = {
ExtendedFloatingActionButton(
onClick = { onNoteAddClick() },
icon = { Icon(Icons.Filled.Add, contentDescription = "Add") },
text = { Text("Add") }
)
},
) { contentPadding ->
Box(modifier = Modifier.padding(contentPadding)) {
NoteList(notes, onNoteListItemClick = { onNoteListItemClick(it) })
}
}
}
}
@Composable
fun NoteListItem(note: Note, onNoteListItemClick: (note: Note) -> Unit) {
Row(
modifier = Modifier
.fillMaxWidth()
.clickable(onClick = { onNoteListItemClick(note) })
.padding(16.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Text(text = note.icon, fontSize = 32.sp, modifier = Modifier.size(48.dp))
Spacer(modifier = Modifier.width(8.dp))
Column {
Text(text = note.title, fontSize = 18.sp)
Spacer(modifier = Modifier.height(4.dp))
Text(
text = note.content,
fontSize = 14.sp,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
}
}
}
@Composable
fun NoteList(notes: Map<String, Note>, onNoteListItemClick: (note: Note) -> Unit) {
LazyColumn {
items(notes.entries.toList()) { (_, note) ->
NoteListItem(note = note, onNoteListItemClick = onNoteListItemClick)
}
}
}
- Теперь
заметки
извлекаются изAppViewModel
. - Вместо того чтобы определять события нажатия в композитах, мы передали их в качестве аргументов.
- Для разработки пользовательского интерфейса мы использовали Compose. Чтобы сделать его более удобным, мы включили
MaterialTheme
в макетScaffold
.
Если вы восстановите приложение, на экране должен появиться список “жестко закодированных” заметок.
Деятельность в форме нот
В этом разделе мы добавим новую активность, которая позволит пользователям добавлять и редактировать заметки.
Начните с создания нового класса FormActivity
со следующим содержимым:
// app/src/main/java.<your_package_name>/FormActivity.kt
package <your.package.name>
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material3.Button
import androidx.compose.material3.ExtendedFloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.unit.dp
class FormActivity : ComponentActivity() {
private val viewModel = AppViewModel.getInstance()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val objectId = intent.getStringExtra("objectId")
val note = if (objectId !== null) viewModel.notes.value[objectId] else null
setContent {
FormActivityContent(
note,
onNoteAddClick = { icon: String, title: String, content: String ->
if (note !== null) return@FormActivityContent
val newNote = Note(
icon = icon,
title = title,
content = content,
)
newNote.objectId = Note.generateObjectId()
viewModel.notes.value += (newNote.objectId!! to newNote)
finish()
},
onNoteSaveClick = { icon: String, title: String, content: String ->
if (note === null) return@FormActivityContent
val updatedNote = note.copy()
updatedNote.icon = icon
updatedNote.title = title
updatedNote.content = content
viewModel.notes.value += (updatedNote.objectId!! to updatedNote)
finish()
},
onNoteDeleteClick = {
if (note === null) return@FormActivityContent
viewModel.notes.value = viewModel.notes.value.filter {
it.value.objectId != note.objectId
}
finish()
},
)
}
}
}
@Composable
fun FormActivityContent(
note: Note?,
onNoteAddClick: (icon: String, title: String, content: String) -> Unit,
onNoteSaveClick: (icon: String, title: String, content: String) -> Unit,
onNoteDeleteClick: () -> Unit,
) {
MaterialTheme {
Scaffold(
topBar = {
TopAppBar(title = { Text(note?.let { "Edit Note" } ?: ("Add Note")) })
},
floatingActionButton = {
if (note !== null) {
ExtendedFloatingActionButton(
onClick = { onNoteDeleteClick() },
icon = { Icon(Icons.Filled.Delete, "Delete") },
text = { Text("Delete") },
)
}
},
) { contentPadding ->
Box(modifier = Modifier.padding(contentPadding)) {
NoteForm(note = note, onNoteSave = { icon, title, content ->
if (note === null) {
onNoteAddClick(icon, title, content)
} else {
onNoteSaveClick(icon, title, content)
}
})
}
}
}
}
@Composable
fun NoteForm(
note: Note?,
onNoteSave: (icon: String, title: String, content: String) -> Unit
) {
var icon by remember { mutableStateOf(TextFieldValue(note?.icon ?: "")) }
var title by remember { mutableStateOf(TextFieldValue(note?.title ?: "")) }
var content by remember { mutableStateOf(TextFieldValue(note?.content ?: "")) }
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp)
) {
TextField(
label = { Text(text = "Icon") },
value = icon,
onValueChange = { icon = it },
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(16.dp))
TextField(
label = { Text(text = "Title") },
value = title,
onValueChange = { title = it },
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(16.dp))
TextField(
label = { Text(text = "Content") },
value = content,
onValueChange = { content = it },
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(16.dp))
Button(
onClick = { onNoteSave(icon.text, title.text, content.text) },
Modifier.fillMaxWidth()
) {
Text(text = "Save")
}
}
}
- Эта форма используется как для добавления, так и для редактирования заметок. Чтобы определить действие, мы сравниваем
objectId == null
. Еслиnull
, то это действие добавления, в противном случае – редактирования. - Если
objectId !== null
, мы получаемзаметку
из состояния и заполняем форму. - Чтобы
MutableState
работал правильно, мы должны были рассматривать его содержимое как неизменяемое. Именно поэтому мы иногда копировали содержимое, а не изменяли его. - Мы обработали состояние формы Compose с помощью функции
mutableStateOf()
.
Затем зарегистрируйте FormActivity
в нижней части приложения
в файле AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application>
<!-- ... -->
<activity android:name=".FormActivity"/>
</application>
</manifest>
Наконец, создайте новое намерение
на onNoteListItemClick
и onNoteAddClick
в файле MainActivity.kt:
// app/src/main/java.<your_package_name>/MainActivity.kt
class MainActivity : ComponentActivity() {
// ...
override fun onCreate(savedInstanceState: Bundle?) {
// ...
setContent {
MainActivityContent(
viewModel = viewModel,
onNoteListItemClick = {
// triggers the edit action, since `objectId` is provided
val intent = Intent(context, FormActivity::class.java)
intent.putExtra("objectId", it.objectId)
context.startActivity(intent)
},
onNoteAddClick = {
// triggers the add action, since no `objectId` is present
val intent = Intent(context, FormActivity::class.java)
context.startActivity(intent)
},
)
}
}
}
Не забудьте импортировать Intent
в верхней части файла:
import android.content.Intent
Если вы восстановите приложение, то заметите, что теперь у нас есть работающее приложение. Приложение позволяет нам добавлять заметки, редактировать их и удалять.
Единственная проблема заключается в том, что перезапуск приложения сбрасывает его состояние (к “жестко закодированным” заметкам).
В следующем разделе мы подключим приложение к бэкенду Back4app. Это позволит нам сохранять состояние и синхронизировать его между несколькими устройствами.
Установите Parse SDK
Как вы, наверное, знаете, Back4app основан на платформе Parse. Если мы хотим взаимодействовать с базой данных Back4app или Back4app в целом, мы должны установить Parse SDK.
Начните с добавления репозитория JitPack в файл settings.gradle:
// settings.gradle
pluginManagement {
repositories {
// ...
maven { url "https://jitpack.io" }
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
// ...
maven { url "https://jitpack.io" }
}
}
Затем добавьте Android Parse SDK в build.gradle на уровне приложений:
// app/build.gradle
dependencies {
// ...
implementation "com.github.parse-community.Parse-SDK-Android:parse:4.2.0"
}
Синхронизируйте настройки Gradle и убедитесь в отсутствии ошибок.
Настройка Parse SDK
Чтобы подключиться к бэкенду Back4app, вам нужно предоставить Parse SDK идентификатор приложения и клиентский ключ. Чтобы получить учетные данные, перейдите в приложение Back4app и выберите “Настройки приложения > Безопасность и ключи” на боковой панели.
Затем добавьте их в файл strings.xml следующим образом:
<!-- app/src/main/res/values/strings.xml -->
<resources>
<string name="app_name">back4app-android-app</string>
<string name="back4app_server_url">https://parseapi.back4app.com/</string>
<string name="back4app_app_id">your_parse_app_id</string>
<string name="back4app_client_key">your_parse_client_key</string>
</resources>
Не забудьте заменить
your_parse_app_id
иyour_parse_client_key
на свои учетные данные.
Затем измените файл AndroidManifest.xml, чтобы включить доступ в интернет и прикрепить метаданные учетных данных:
<!-- app/src/main/AndroidManifest.xml -->
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<!-- these two permissions enable internet access -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<application>
<!-- ... -->
<!-- newly added metadata -->
<meta-data
android:name="com.parse.SERVER_URL"
android:value="@string/back4app_server_url" />
<meta-data
android:name="com.parse.APPLICATION_ID"
android:value="@string/back4app_app_id" />
<meta-data
android:name="com.parse.CLIENT_KEY"
android:value="@string/back4app_client_key" />
</application>
</manifest>
Последнее, что нам нужно сделать, это инициализировать Parse. Чтобы убедиться, что Parse инициализируется до начала любой деятельности, мы создадим новый класс App
, который наследуется от класса Application
.
Создайте App.kt и инициализируйте Parse следующим образом:
// app/src/main/java/<your_package_name>/App.kt
package <your.package.name>
import android.app.Application
import com.parse.Parse
class App : Application() {
override fun onCreate() {
super.onCreate()
Parse.initialize(
Parse.Configuration.Builder(this)
.applicationId(getString(R.string.back4app_app_id))
.clientKey(getString(R.string.back4app_client_key))
.server(getString(R.string.back4app_server_url))
.build()
)
}
}
Затем зарегистрируйте класс App
в файле AndroidManifest.xml:
<!-- app/src/main/AndroidManifest.xml -->
<application
android:name=".App"
...
>
<!-- ... -->
</application>
Еще раз пересоберите приложение и проверьте окно Logcat на наличие ошибок. Если ошибок нет, то подключение к Back4app прошло успешно.
Загрузить заметки из Back4app
Последнее, что нам осталось сделать перед тем, как наше приложение будет завершено, – это загрузить заметки из базы данных Back4app и посмотреть, как использовать Parse на практике.
Начните с перехода к модели AppViewModel
. Удалите данные из карты и добавьте блок init
:
// app/src/main/java/<your_package_name>/AppViewModel.kt
package <your.package.name>
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
class AppViewModel : ViewModel() {
val notes: MutableState<Map<String, Note>> = mutableStateOf(mapOf())
init {
val query = com.parse.ParseQuery.getQuery<com.parse.ParseObject>("Note")
query.orderByDescending("createdAt")
query.findInBackground { notes, e ->
if (e == null) {
for (parseNote in notes) {
val note = Note(
objectId = parseNote.objectId,
icon = parseNote.getString("icon")!!,
title = parseNote.getString("title")!!,
content = parseNote.getString("content")!!,
)
this.notes.value += (note.objectId!! to note)
}
} else {
println("Error: ${e.message}")
}
}
}
companion object {
// ...
}
}
Этот код использует Parse SDK для получения заметок из баз данных, преобразует их в класс данных Note
и сохраняет на карте.
Затем добавьте в Note
следующие три метода:
// app/src/main/java/<your_package_name>/Note.kt
package <your.package.name>
import com.parse.ParseObject
import com.parse.ParseQuery
data class Note(
var objectId: String? = null,
var icon: String,
var title: String,
var content: String,
) {
fun addToParse(callback: (objectId: String) -> Unit) {
if (objectId !== null) throw Exception("Note is already saved to Parse!")
val parseNote = ParseObject("Note")
parseNote.put("icon", icon)
parseNote.put("title", title)
parseNote.put("content", content)
parseNote.saveInBackground {
if (it !== null) throw Exception("Error: ${it.message}")
objectId = parseNote.objectId
callback(parseNote.objectId)
}
}
fun updateToParse(callback: (objectId: String) -> Unit) {
if (objectId === null) throw Exception("Note hasn't been saved to Parse yet!")
val query = ParseQuery.getQuery<ParseObject>("Note")
val parseNote = query.get(objectId)
parseNote.put("icon", icon)
parseNote.put("title", title)
parseNote.put("content", content)
parseNote.saveInBackground {
if (it !== null) throw Exception("Error: ${it.message}")
callback(parseNote.objectId)
}
}
fun deleteFromParse(callback: () -> Unit) {
if (objectId === null) throw Exception("Note hasn't been saved to Parse yet!")
val query = ParseQuery.getQuery<ParseObject>("Note")
val parseNote = query.get(objectId)
parseNote.deleteInBackground {
if (it !== null) throw Exception("Error: ${it.message}")
callback()
}
}
}
addToParse()
добавляет новую заметку на сервер Parse с ее деталями. В случае успеха она сохраняет уникальный идентификатор заметки и уведомляет о завершении.updateToParse()
обновляет информацию о существующей заметке на сервере Parse. В случае успеха она сигнализирует о завершении после внесения изменений.deleteFromParse()
удаляет сохраненную заметку с сервера Parse. В случае успеха она подтверждает удаление по завершении.
Наконец, измените методы click в FormActivity
, чтобы они вызывали новые методы:
// app/src/main/java/<your_package_name>/NoteFormActivity.kt
class FormActivity : ComponentActivity() {
// ...
override fun onCreate(savedInstanceState: Bundle?) {
// ...
setContent {
FormActivityContent(
note,
onNoteAddClick = { icon: String, title: String, content: String ->
if (note !== null) return@FormActivityContent
val newNote = Note(
icon = icon,
title = title,
content = content,
)
newNote.addToParse {
viewModel.notes.value += (it to newNote)
finish()
}
},
onNoteSaveClick = { icon: String, title: String, content: String ->
if (note === null) return@FormActivityContent
val updatedNote = note.copy()
updatedNote.icon = icon
updatedNote.title = title
updatedNote.content = content
updatedNote.updateToParse {
viewModel.notes.value += (it to updatedNote)
finish()
}
},
onNoteDeleteClick = {
if (note === null) return@FormActivityContent
viewModel.notes.value = viewModel.notes.value.filter {
it.value.objectId != note.objectId
}
note.deleteFromParse {
finish()
}
},
)
}
}
}
Вот и все!
Теперь приложение полностью работает и синхронизировано с бэкендом Back4app. Попробуйте поиграть с приложением, изменяя данные и проверяя, отражаются ли изменения в представлении базы данных.
Заключение
В этой статье мы успешно создали мобильный бэкенд и подключились к нему из нашего приложения для Android. Для бэкенда мы использовали решение BaaS от Back4app, а для фронтенда – Kotlin с Jetpack Compose.
К этому моменту вы должны хорошо понимать, как работают мобильные бэкенды, и быть в состоянии создать свой собственный. Ознакомьтесь с окончательным вариантом исходного кода в репозитории back4app-android-app.