如何为 Android 应用程序创建后台?
在本文中,我们将讨论 Android — 最流行的操作系统之一。我们将探讨 Android 开发的利弊、移动应用程序的后台选项,并教您如何构建自己的移动后台。
主要收获
- 安卓的主导地位:作为一款开源操作系统,安卓为大约 70% 的移动设备提供动力,活跃用户超过 30 亿。
- 应用程序后端选项:对于移动应用程序后端,开发人员可以选择基础设施即服务(IaaS)、平台即服务(PaaS)或后端即服务(BaaS)。
- 构建后台的步骤:我们将在文章末尾提供如何使用 BaaS 平台制作 Android 后台的详细教程和源代码。
什么是安卓?
安卓是一种基于 Linux 的免费开源操作系统。它主要是为智能手机和平板电脑等移动设备设计的,但现在也用于智能电视、嵌入式系统、游戏机等。
安卓系统的开发始于 2003 年,由安卓公司(Android Inc.该公司最初想为数码相机开发一个操作系统,但很快转向移动操作系统的开发,以拓展更广阔的市场。
2005 年,公司及其员工被谷歌收购。第一个版本的安卓系统于 2008 年发布。
尽管 Android 是开源的,但大多数移动设备运行的是谷歌的专有版本。他们的版本预装了 Google Chrome、YouTube、Google TV 和 Gmail 等软件。
由于安卓系统具有强大的定制选项,许多制造商也会为安卓系统更换皮肤,以更好地代表自己的公司。这就是为什么 OnePlus 的安卓系统看起来与 Pixel 的安卓系统截然不同。
自 2013 年以来,安卓一直是最流行的操作系统。大约 70% 的移动设备都在使用该系统,月活跃用户超过 30 亿。
此外,Google Play Store 还可让您访问 300 多万个移动应用程序。继续阅读,了解如何为 Android 应用程序创建后台。
安卓开发的优势
让我们来探讨一下为 Android 开发的一些好处。
跨平台
通过为安卓系统开发,您可以针对各种设备进行开发。这包括手机、可穿戴设备、智能电视、游戏机等。如果您知道如何编写移动应用程序,那么开发可穿戴设备或智能电视应用程序也不成问题。
巨大的市场
如前所述,与 iOS 的 30% 市场份额相比,Android 的市场份额更大,达到 70%。通过开发安卓应用程序,您将自动获得更广泛的受众。
此外,安卓应用程序以投资少、回报高而著称。与 iOS 不同的是,它还不涉及开发者年费。
可定制性
与其他操作系统相比,安卓设备具有很高的可定制性。它允许你改变任何你能想象到的东西。
此外,Android 还允许您轻松将应用程序与其他第三方服务集成。
社区
Android 拥有庞大的开源开发者社区。此外,它还配备了许多对开发者友好的工具,如Android Studio、ADB 和Logcat,让您可以轻松编写应用程序。
如果你遇到问题,可以通过几个平台寻求帮助,包括GitHub、StackOverflow、Reddit 和其他以 Android 为中心的社区。
安卓开发的局限性
以下是 Android 开发的一些弊端。
安全
与 iOS 相比,安卓系统的安全性较低,而且不遵循严格的安全协议。由于安卓是开源系统,每周都会检测到安全漏洞。这使得黑客有能力在这些漏洞被修补之前加以利用。
安卓设备也可以通过 root 获得超级用户权限。虽然它能让你的设备更强大,但也有风险,因为它会禁用一些内置的安全措施。
复杂性
安卓设备的形状和大小各不相同,这固然很好,但在为多种设备类型开发安卓应用程序时,这可能是一个巨大的缺陷。
为了确保您的应用程序与尽可能多的设备兼容,您必须采用响应式设计,考虑不同设备的硬件等等。
高级应用程序
与App Store 相比,高级应用程序在Google Play Store 上的成功率较低。与 iOS 用户相比,Android 用户往往在应用程序上花费较少,这已不是什么秘密。如果您正在开发一款高级应用,请将 Android 作为您的第二选择。
安卓应用程序的后台选项
安卓应用程序的最佳后台是什么?移动应用程序的后端可以托管在自己的基础设施上,也可以部署到云服务中。最流行的移动后端云计算模式包括
- 基础设施即服务(IaaS)
- 平台即服务(PaaS)
- 后台即服务(BaaS)
如下图所示,每个选项涵盖不同的抽象层。
让我们详细了解每个选项,帮助您为后台应用程序选择最合适的云模式。
基础设施即服务(IaaS)
基础设施即服务(IaaS)是最不抽象的云计算模式。在这种模式下,供应商通过高级 API 或直观的仪表板向用户提供虚拟化资源,如服务器、网络、存储和操作系统。
IaaS 的最大优点是用户可以完全控制整个基础设施。IaaS 是最灵活、可扩展的模式,但也是最难管理的模式。如果选择这种方式,很可能需要一两个系统管理员。
平台即服务(PaaS)
平台即服务(PaaS)是一种云计算模式,旨在帮助用户开发、管理和部署应用程序。
除了提供基础设施,PaaS 还提供用户友好型工具,用于开发、定制和测试应用程序。
利用 PaaS,您可以专注于软件和用户体验,而不必担心底层基础设施。
此外,PaaS 还能确保您的应用程序按需扩展,并负责备份等工作。PaaS 的缺点是控制水平较低、有被供应商锁定的风险,而且成本相对较高。
后台即服务(BaaS)
后端即服务(BaaS)通过提供成熟的后端解决方案,使开发的后端部分实现自动化。
BaaS 功能包括用户管理、数据库、身份验证、社交集成、推送通知、API、SDK 等。
BaaS 提供 IaaS 和 PaaS 的所有优点,同时还提供额外的功能。利用 BaaS 的团队往往能更快地发布产品、削减工程成本并构建更好的软件。
BaaS 的缺点包括控制和定制水平较低,以及可能被非开源平台的供应商锁定。
如何为 Android 应用程序制作后台?
在本节文章中,我们将介绍如何构建基于 Back4app 的后台应用程序,并从 Android 应用程序连接到它。
先决条件
- 拥有Kotlin和 Android 开发经验。
- 基本了解移动后台即服务。
- 在本地计算机上安装Java和Android Studio。
什么是 Back4app?
Back4app 是为现代应用程序构建后端并加快开发进程的绝佳平台。
它配备了实用的服务器端功能,如用户管理、实时数据库、社交集成、云代码功能、推送通知、应用程序接口等!
通过使用 Back4app,您可以将大部分后台工作外包,专注于应用程序的关键方面,加快安卓应用程序的后台开发。
您无需处理后台的底层基础设施、后台服务器、扩展、维护等问题。
最重要的是,Back4app 提供免费层级,非常适合实验和测试平台。随着应用程序的发展,您可以按月付费升级到高级计划。
项目介绍
在本文中,我们将构建一个简单的笔记应用程序。该应用程序将允许用户添加、编辑和删除笔记。笔记将存储在 Back4app 数据库中,并通过Parse SDK 进行操作。
我们将使用 Kotlin 编程语言来构建应用程序。在用户界面方面,我们将使用Jetpack Compose– Android 用于构建原生用户界面的现代工具包。
创建 Back4app 应用程序
作为开发安卓应用程序后台的第一步,您需要一个 Back4app 账户。如果您还没有账户,请注册。
登录 Back4app 账户后,您将被重定向到应用程序视图。点击 “创建新应用程序”,初始化应用程序创建过程。
Back4app 平台提供两种解决方案:
- 后台即服务(BaaS)–强大的后台解决方案
- 容器即服务 (CaaS) — 管理容器(尤其是网络应用程序)的平台
考虑到我们要为移动应用程序构建后台,我们将采用 “后台即服务”。
给你的应用程序起一个好听又有内涵的名字,选择 “NoSQL “作为数据库,然后点击 “创建”。这是部署 Android 应用程序后台的重要一步。
Back4app 需要一些时间来准备应用程序所需的一切。这包括数据库、用户管理、扩展、配置等。应用程序准备就绪后,您将被重定向到应用程序的数据库视图。
设计数据库
接下来,我们来设计数据库。这是开发 Android 应用程序后台的必要步骤。
由于我们构建的是一个简单的笔记应用程序,因此只需要一个类。继续点击 “创建类”,将其命名为 “Note
“,启用 “公共读写”,然后点击 “创建类并添加列”。
接下来,在新创建的类中添加以下三个字段:
+-------------+-------------+--------------------+----------+
| Data type | Name | Default value | Required |
+-------------+-------------+--------------------+----------+
| String | icon | <leave blank> | yes |
+-------------+-------------+--------------------+----------+
| String | title | <leave blank> | yes |
+-------------+-------------+--------------------+----------+
| String | content | <leave blank> | yes |
+-------------+-------------+--------------------+----------+
最后,点击 “添加行 “按钮,在数据库中填充一些示例数据。如果您没有任何想法,也可以导入这些数据。
很好,后台就是这样。
代码前端
在本节文章中,我们将引导一个新的 Android 应用程序、设置ViewModel、实现用户界面、安装和配置 Parse SDK,最后从 Back4app 实时数据库获取数据。
初始项目
如前提条件部分所述,以下步骤需要安装 Android Studio。如果尚未安装,请下载。
首先打开 Android Studio,点击 “新建项目 “按钮。
然后选择 “空活动 “作为项目模板,点击 “下一步”。
要创建项目,必须提供名称和软件包名称。我建议您使用AndroidApp
作为项目名称,使用反向域名作为项目软件包名称。
完成所有配置后,点击 “完成 “创建项目。
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
。但在此之前,我们必须创建一个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 的对象 ID。 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 }
}
}
}
}
- 我们使用 Compose 的
MutableState
在数据发生变化时触发用户界面更新。 MutableState
包含一个对象 ID
和注释
的映射表
,我们在其中填充了数据。- 为了确保
AppViewModel
只有一个实例,我们使用了单例模式。
现在,我们可以在活动中通过AppViewModel.getInstance()
访问AppViewModel
实例。
主要活动
接着,用以下代码替换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
。如果为空
,则为添加操作,否则为编辑操作。 - 如果
objectId !== null
,我们将从状态中获取注释
并填充表单。 - 为了使
MutableState
正常工作,我们必须将其内容视为不可变的。这就是我们有时复制内容而不是修改内容的原因。 - 我们通过
mutableStateOf()
处理 Compose 表单状态。
接下来,在AndroidManifest.xml 中的应用程序
底部注册FormActivity
:
<?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>
最后,在MainActivity.kt 中为onNoteListItemClick
和onNoteAddClick
创建一个新Intent
:
// 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。
首先在settings.gradle 中添加JitPack 仓库:
// settings.gradle
pluginManagement {
repositories {
// ...
maven { url "https://jitpack.io" }
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
// ...
maven { url "https://jitpack.io" }
}
}
接下来,在应用程序级的build.gradle 中添加 Android Parse SDK:
// app/build.gradle
dependencies {
// ...
implementation "com.github.parse-community.Parse-SDK-Android:parse:4.2.0"
}
同步 Gradle 设置,确保没有错误。
配置 Parse SDK
要连接到 Back4app 后台,您必须向 Parse SDK 提供您的应用程序 ID 和客户端密钥。要获取凭证,请导航至您的 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()
)
}
}
然后在AndroidManifest.xml 中注册App
类:
<!-- 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 从数据库中获取笔记,将其转换为笔记
数据类,并保存到地图中。
接下来,在"
注意 “中添加以下三种方法:
// 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 服务器中删除已保存的注释。如果成功,它会在完成后确认删除。
最后,修改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 应用程序连接到它。我们在后端使用了 Back4app 的 BaaS 解决方案,在前端使用了 Kotlin 和 Jetpack Compose。
现在,你应该对移动后端工作原理有了一定的了解,并能构建自己的移动后端了。在back4app-android-app软件仓库中查看最终源代码。