模块化结构组件包含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模块化结构组件内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论