你有没有想过如何制作 Facebook Heads 和其他应用程序使用的那些浮动窗口?您是否曾经想在您的应用程序中使用相同的技术?这很容易,我将指导您完成整个过程。
在本文中,我将教您如何使用 Jetpack Compose 和 Room 构建简单的主应用程序。
理念
我们需要一个想法来应用浮动技术。让我们构建一个允许快速记笔记的应用程序。这是一个完美的案例。为了写一个快速的笔记,你通常不想离开你当前的任务。
让我们将其实现为具有永久通知的长期运行服务 - 随时准备好在需要时提供服务。用户点击我们的通知并开始添加注释。
对于您的应用,您可以更改此行为。不需要长期运行的服务。
主应用
好吧,我们需要从乞讨开始。让我们先构建主应用程序。它使我们能够在现实生活场景中展示集成过程。
我决定使用Kotlin、Jetpack Compose和Room,并构建一个非常简单的笔记应用程序。
顺便说一句,您需要将 Android Studio Canary 安装为 Jetpack Compose,目前在稳定版本中不可用。
Room
Room持久性库在SQLite 之上提供了一个抽象层,以允许更强大的数据库访问,同时利用 SQLite 的全部功能。
让我们从一个简单的实体开始我们的笔记:
@Entity
data class Note(
@PrimaryKey val id: Int,
@ColumnInfo(name = "content") val content: String
)
以及对应的DAO:
@Dao
interface NotesDao {
@Query("SELECT * FROM note")
fun getAll(): List<Note>
@Insert
fun insert(note: Note)
@Delete
fun delete(note: Note)
}
访问我们数据的最后一个缺失部分是AppDatabase类。同样,它非常简单:
@Database(entities = arrayOf(Note::class), version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun notes(): NotesDao
}
视图模型
现在,通过Jetpack Compose 来ViewModel访问我们的数据。MutableState更改变量会自动运行使用它notes的 's 的重组。@Composable
Room 是使用Kotlin 协程访问的,因为我们无法在主线程上调用 SQLite。但是,仅使用基本方法,因为更复杂的场景超出了本文的范围。
class NotesViewModel(application: Application) : AndroidViewModel(application) {
private val db = Room.databaseBuilder(
application.applicationContext,
AppDatabase::class.java,
"db-notes"
).build()
var notes by mutableStateOf(listOf<Note>())
private set
// Load initial data from Room asynchronously.
init {
GlobalScope.launch {
val items = db.notes().getAll()
viewModelScope.launch { notes = items }
}
}
fun addNote(note: String) {
// Generate ID in a simple way - from timestamp.
val noteObj = Note(
(System.currentTimeMillis() % Int.MAX_VALUE).toInt(),
note
)
notes = notes + listOf(noteObj)
GlobalScope.launch { db.notes().insert(noteObj) }
}
fun removeNote(note: Note) {
notes = notes - listOf(note)
GlobalScope.launch { db.notes().delete(note) }
}
}
Composable
同样,保持简单并只创建两个复杂@Composable的一个用于添加注释,第二个用于列出和删除它们。
AddNote Composable
只是一个带有加号按钮的文本字段。而已。
@Composable
fun AddNote(title: String, onNoteAdded: (String) -> Unit) {
Row {
val text = remember { mutableStateOf(TextFieldValue("")) }
TextField(
value = text.value,
onValueChange = { text.value = it },
label = { Text(title) },
modifier = Modifier
.weight(1f, true)
.padding(16.dp, 16.dp, 8.dp, 16.dp)
)
Button(
onClick = {
val newNote = text.value.text
if (newNote.isNotBlank()) {
onNoteAdded(newNote)
text.value = TextFieldValue("")
}
},
modifier = Modifier
.padding(8.dp, 16.dp, 16.dp, 16.dp)
.gravity(Alignment.CenterVertically)
) {
Icon(
asset = Icons.Filled.Add,
modifier = Modifier.size(24.dp)
)
}
}
}
ShowNotes Composable
Composable会LazyColumnFor自动列出我们所有的注释,当items来自视图模型时,会在更改时更新它。
@Composable
fun ShowNotes(items: List<Note>, onNodeRemoved: (Note) -> Unit) {
LazyColumnFor(items = items) {
Row {
Text(
text = it.content,
modifier = Modifier
.padding(16.dp, 4.dp, 4.dp, 4.dp)
.weight(1f, true)
.gravity(Alignment.CenterVertically)
)
TextButton(
onClick = {
onNodeRemoved(it)
},
contentPadding = InnerPadding(0.dp),
modifier = Modifier
.padding(4.dp, 4.dp, 16.dp, 4.dp)
.gravity(Alignment.CenterVertically)
) {
Icon(
asset = Icons.Filled.Delete,
modifier = Modifier.size(24.dp)
)
}
}
}
}
Activity - 粘贴
我们MainActivity只是将上面的所有代码粘合在一起并显示我们的两个可组合项。
class MainActivity : AppCompatActivity() {
private val notesViewModel by viewModels<NotesViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Column {
AddNote(getString(R.string.add_note)) {
notesViewModel.addNote(it)
}
ShowNotes(notesViewModel.notes) {
notesViewModel.removeNote(it)
}
}
}
}
}
在我们的示例应用程序中,您可以在源代码中注意到它,我通过在我的根 build.gradle 中包含以下行来使用 Localazy :
repositories {
maven { url "https://maven.localazy.com/repository/release/" }
}
dependencies {
classpath "com.localazy:gradle:1.5.2"
}
在我的应用程序的 build.gradle 中:
apply plugin: 'com.localazy.gradle'
localazy {
readKey "a8922414862262844150-..."
writeKey "a8922414862262844150-..."
}
这已经足够了。