模块化布局组件包罗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>
复制代码- <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" />
复制代码- 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 应用架构。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |