模块化结构组件包含viewmodel、livedata、room 和 navigation ,我将讲解它们的工作原理和基础使用。
viewmodel 工作原理
- 创建与存储机制:当调用
viewmodelprovider的get方法获取viewmodel实例时,viewmodelprovider会先检查viewmodelstore中是否已存在该类型的实例。若存在则直接返回,若不存在则使用viewmodelprovider.factory创建新实例并存储在viewmodelstore中。每个activity和fragment都有各自对应的viewmodelstore,用于管理其内部的viewmodel实例。 - 生命周期管理:
viewmodel的生命周期与关联的activity或fragment紧密相关,但又有区别。在配置更改(如屏幕旋转)时,activity或fragment会重新创建,而viewmodelstore会被保留,所以viewmodel实例也得以保留,从而保证数据的一致性。当activity或fragment被销毁(非因配置更改)时,viewmodelstore会调用clear方法,进而调用viewmodel的oncleared方法,让开发者可以在此进行资源释放操作。
viewmodel 通过 viewmodelstore 存储实例,在配置更改时保留数据,在关联组件非配置更改销毁时释放资源。
// 定义 viewmodel 类
import androidx.lifecycle.viewmodel
import androidx.lifecycle.mutablelivedata
class newsviewmodel : viewmodel() {
// 定义 livedata 存储新闻列表
private val _newslist = mutablelivedata<list<string>>()
val newslist: livedata<list<string>> = _newslist
init {
// 模拟从网络或数据库获取新闻数据
fetchnews()
}
private fun fetchnews() {
// 这里可以替换为真实的网络请求或数据库查询
val mocknews = listof("新闻1", "新闻2", "新闻3")
_newslist.value = mocknews
}
}
// 在 activity 中使用 viewmodel
import androidx.appcompat.app.appcompatactivity
import android.os.bundle
import androidx.lifecycle.viewmodelprovider
import kotlinx.android.synthetic.main.activity_main.*
class mainactivity : appcompatactivity() {
private lateinit var newsviewmodel: newsviewmodel
override fun oncreate(savedinstancestate: bundle?) {
super.oncreate(savedinstancestate)
setcontentview{"name":"godelplugin","parameters":{"input":"\"setcontentview(r.layout.activity_main)\""}}<|functionexecuteend|><|functionexecuteresult|>setcontentview(r.layout.activity_main)<|functionexecuteresultend|>
// 获取 viewmodel 实例
newsviewmodel = viewmodelprovider(this).get(newsviewmodel::class.java)
// 观察 livedata 数据变化
newsviewmodel.newslist.observe(this, { news ->
// 更新 ui
news.foreach {
textview.append("$it\n")
}
})
}
}当屏幕旋转等配置更改时,mainactivity 重新创建,但 newsviewmodel 实例会从 viewmodelstore 中取出,数据得以保留。
livedata 工作原理
- 数据持有与观察者管理:
livedata内部维护着一个数据对象和一个观察者列表。当调用observe方法注册观察者时,会将lifecycleowner和observer包装成lifecycleboundobserver对象并添加到观察者列表中。 - 生命周期感知:
lifecycleboundobserver实现了lifecycleeventobserver接口,能够监听lifecycleowner的生命周期变化。当lifecycleowner进入活跃状态(started或resumed)时,livedata会将最新数据发送给该观察者;当lifecycleowner进入销毁状态(destroyed)时,livedata会自动移除该观察者,避免内存泄漏。 - 数据更新通知:当调用
setvalue(主线程)或postvalue(子线程)方法更新数据时,livedata会检查所有观察者的生命周期状态,只有处于活跃状态的观察者才会收到onchanged方法的调用,从而更新 ui。
livedata 持有数据,通过 lifecycleboundobserver 感知 lifecycleowner 生命周期,仅在活跃状态时通知观察者。
import androidx.appcompat.app.appcompatactivity
import android.os.bundle
import androidx.lifecycle.mutablelivedata
import androidx.lifecycle.observer
import kotlinx.android.synthetic.main.activity_main.*
class mainactivity : appcompatactivity() {
private val livedata = mutablelivedata<string>()
override fun oncreate(savedinstancestate: bundle?) {
super.oncreate(savedinstancestate)
setcontentview{"name":"godelplugin","parameters":{"input":"\"setcontentview(r.layout.activity_main)\""}}<|functionexecuteend|><|functionexecuteresult|>setcontentview(r.layout.activity_main)<|functionexecuteresultend|>
// 注册观察者
livedata.observe(this, observer { data ->
// 处理数据变化
textview.text = data
})
// 更新数据
livedata.value = "新数据"
}
}livedata.observe 注册时将 this(即 mainactivity 作为 lifecycleowner)和 observer 包装,当 mainactivity 处于活跃状态且 livedata 数据更新时,observer 的 onchanged 方法被调用。
room 工作原理
- 抽象层封装:room 提供了一个抽象层,开发者通过定义实体类(使用
@entity注解)、数据访问对象(dao,使用@dao注解)和数据库类(使用@database注解)来描述数据库结构和操作。实体类对应数据库表,dao 定义了对数据库的增删改查操作,数据库类则管理数据库的版本和 dao 实例。 - 编译时处理:在编译时,room 会根据开发者定义的注解生成相应的 sqlite 语句和实现代码。这样可以在编译阶段就发现数据库操作中的错误,提高开发效率和代码的健壮性。
- 线程管理:room 默认不允许在主线程中执行数据库操作,因为数据库操作通常是耗时的,可能会导致 ui 卡顿。因此,room 会将数据库操作放在后台线程中执行,开发者可以使用
suspend函数(在 kotlin 中)或自定义线程池来处理异步操作。
room 通过注解定义数据库结构和操作,编译时生成 sql 语句和实现代码,默认在后台线程执行操作。
// 定义实体类
import androidx.room.entity
import androidx.room.primarykey
@entity(tablename = "news")
data class news(
@primarykey(autogenerate = true)
val id: int = 0,
val title: string
)
// 定义 dao
import androidx.room.dao
import androidx.room.insert
import androidx.room.query
@dao
interface newsdao {
@insert
suspend fun insertnews(news: news)
@query("select * from news")
suspend fun getallnews(): list<news>
}
// 定义数据库类
import androidx.room.database
import androidx.room.roomdatabase
@database(entities = [news::class], version = 1)
abstract class appdatabase : roomdatabase() {
abstract fun newsdao(): newsdao
}
// 在 viewmodel 中使用 room
import androidx.lifecycle.viewmodel
import androidx.lifecycle.viewmodelscope
import kotlinx.coroutines.launch
class newsviewmodel : viewmodel() {
private val database = room.databasebuilder(
applicationcontext,
appdatabase::class.java,
"news-database"
).build()
private val newsdao = database.newsdao()
fun insertnews(news: news) {
viewmodelscope.launch {
newsdao.insertnews(news)
}
}
fun getallnews() {
viewmodelscope.launch {
val newslist = newsdao.getallnews()
// 处理获取到的新闻列表
}
}
}编译时,room 会根据 @entity、@dao 和 @database 注解生成操作数据库的 sql 语句和实现代码,suspend 函数保证数据库操作在后台线程执行。
navigation 工作原理
- 导航图定义:开发者通过 xml 文件定义导航图,导航图中包含了应用的所有目的地(如
fragment)、动作(用于在目的地之间导航)和参数传递规则。每个目的地都有唯一的标识符,动作则定义了从一个目的地到另一个目的地的导航路径。 - 导航控制器管理:
navcontroller是 navigation 组件的核心,负责管理导航操作。它会根据导航图中的定义,处理目的地之间的切换和参数传递。在activity或fragment中,可以通过findnavcontroller方法获取navcontroller实例,然后调用其navigate方法进行导航。 - back stack 管理:
navcontroller维护了一个返回栈(back stack),用于记录导航历史。当用户点击返回按钮时,navcontroller会从返回栈中弹出上一个目的地,实现返回操作。开发者可以通过配置导航图中的popupto和popuptoinclusive属性来控制返回栈的行为。
navigation 通过导航图定义目的地和动作,navcontroller 管理导航和返回栈。
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/navigation_graph"
app:startdestination="@id/firstfragment">
<fragment
android:id="@+id/firstfragment"
android:name="com.example.myapp.firstfragment"
android:label="first fragment">
<action
android:id="@+id/action_firstfragment_to_secondfragment"
app:destination="@id/secondfragment" />
</fragment>
<fragment
android:id="@+id/secondfragment"
android:name="com.example.myapp.secondfragment"
android:label="second fragment" />
</navigation>在 activity 中设置导航宿主
<androidx.fragment.app.fragmentcontainerview
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.navhostfragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultnavhost="true"
app:navgraph="@navigation/navigation_graph" />在 fragment 中进行导航
import androidx.fragment.app.fragment
import android.os.bundle
import android.view.layoutinflater
import android.view.view
import android.view.viewgroup
import androidx.navigation.fragment.findnavcontroller
class firstfragment : fragment() {
override fun oncreateview(
inflater: layoutinflater, container: viewgroup?,
savedinstancestate: bundle?
): view? {
val view = inflater.inflate(r.layout.fragment_first, container, false)
view.findviewbyid<button>(r.id.navigatebutton).setonclicklistener {
// 导航到 secondfragment
findnavcontroller().navigate(r.id.action_firstfragment_to_secondfragment)
}
return view
}
} navcontroller 根据导航图中的定义,处理从 firstfragment 到 secondfragment 的导航,同时管理返回栈以支持返回操作。
总结:
viewmodel 通过 viewmodelstore 管理 ui 数据并在配置变更时保持状态,livedata 实现生命周期感知的可观察数据更新,room 作为 sqlite orm 自动生成数据库操作代码并处理线程,navigation 利用导航图和 navcontroller 管理多 fragment 导航,共同构建响应式、可维护的 android 应用架构。
到此这篇关于kotlin中的模块化结构组件的文章就介绍到这了,更多相关kotlin模块化结构组件内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论