kotlin中的模塊化結(jié)構(gòu)組件及工作原理
模塊化結(jié)構(gòu)組件包含ViewModel、LiveData、Room 和 Navigation ,我將講解它們的工作原理和基礎(chǔ)使用。
ViewModel 工作原理
- 創(chuàng)建與存儲(chǔ)機(jī)制:當(dāng)調(diào)用
ViewModelProvider的get方法獲取ViewModel實(shí)例時(shí),ViewModelProvider會(huì)先檢查ViewModelStore中是否已存在該類型的實(shí)例。若存在則直接返回,若不存在則使用ViewModelProvider.Factory創(chuàng)建新實(shí)例并存儲(chǔ)在ViewModelStore中。每個(gè)Activity和Fragment都有各自對(duì)應(yīng)的ViewModelStore,用于管理其內(nèi)部的ViewModel實(shí)例。 - 生命周期管理:
ViewModel的生命周期與關(guān)聯(lián)的Activity或Fragment緊密相關(guān),但又有區(qū)別。在配置更改(如屏幕旋轉(zhuǎn))時(shí),Activity或Fragment會(huì)重新創(chuàng)建,而ViewModelStore會(huì)被保留,所以ViewModel實(shí)例也得以保留,從而保證數(shù)據(jù)的一致性。當(dāng)Activity或Fragment被銷毀(非因配置更改)時(shí),ViewModelStore會(huì)調(diào)用clear方法,進(jìn)而調(diào)用ViewModel的onCleared方法,讓開發(fā)者可以在此進(jìn)行資源釋放操作。
ViewModel 通過(guò) ViewModelStore 存儲(chǔ)實(shí)例,在配置更改時(shí)保留數(shù)據(jù),在關(guān)聯(lián)組件非配置更改銷毀時(shí)釋放資源。
// 定義 ViewModel 類
import androidx.lifecycle.ViewModel
import androidx.lifecycle.MutableLiveData
class NewsViewModel : ViewModel() {
// 定義 LiveData 存儲(chǔ)新聞列表
private val _newsList = MutableLiveData<List<String>>()
val newsList: LiveData<List<String>> = _newsList
init {
// 模擬從網(wǎng)絡(luò)或數(shù)據(jù)庫(kù)獲取新聞數(shù)據(jù)
fetchNews()
}
private fun fetchNews() {
// 這里可以替換為真實(shí)的網(wǎng)絡(luò)請(qǐng)求或數(shù)據(jù)庫(kù)查詢
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 實(shí)例
newsViewModel = ViewModelProvider(this).get(NewsViewModel::class.java)
// 觀察 LiveData 數(shù)據(jù)變化
newsViewModel.newsList.observe(this, { news ->
// 更新 UI
news.forEach {
textView.append("$it\n")
}
})
}
}當(dāng)屏幕旋轉(zhuǎn)等配置更改時(shí),MainActivity 重新創(chuàng)建,但 NewsViewModel 實(shí)例會(huì)從 ViewModelStore 中取出,數(shù)據(jù)得以保留。
LiveData 工作原理
- 數(shù)據(jù)持有與觀察者管理:
LiveData內(nèi)部維護(hù)著一個(gè)數(shù)據(jù)對(duì)象和一個(gè)觀察者列表。當(dāng)調(diào)用observe方法注冊(cè)觀察者時(shí),會(huì)將LifecycleOwner和Observer包裝成LifecycleBoundObserver對(duì)象并添加到觀察者列表中。 - 生命周期感知:
LifecycleBoundObserver實(shí)現(xiàn)了LifecycleEventObserver接口,能夠監(jiān)聽LifecycleOwner的生命周期變化。當(dāng)LifecycleOwner進(jìn)入活躍狀態(tài)(STARTED或RESUMED)時(shí),LiveData會(huì)將最新數(shù)據(jù)發(fā)送給該觀察者;當(dāng)LifecycleOwner進(jìn)入銷毀狀態(tài)(DESTROYED)時(shí),LiveData會(huì)自動(dòng)移除該觀察者,避免內(nèi)存泄漏。 - 數(shù)據(jù)更新通知:當(dāng)調(diào)用
setValue(主線程)或postValue(子線程)方法更新數(shù)據(jù)時(shí),LiveData會(huì)檢查所有觀察者的生命周期狀態(tài),只有處于活躍狀態(tài)的觀察者才會(huì)收到onChanged方法的調(diào)用,從而更新 UI。
LiveData 持有數(shù)據(jù),通過(guò) LifecycleBoundObserver 感知 LifecycleOwner 生命周期,僅在活躍狀態(tài)時(shí)通知觀察者。
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|>
// 注冊(cè)觀察者
liveData.observe(this, Observer { data ->
// 處理數(shù)據(jù)變化
textView.text = data
})
// 更新數(shù)據(jù)
liveData.value = "新數(shù)據(jù)"
}
}liveData.observe 注冊(cè)時(shí)將 this(即 MainActivity 作為 LifecycleOwner)和 Observer 包裝,當(dāng) MainActivity 處于活躍狀態(tài)且 liveData 數(shù)據(jù)更新時(shí),Observer 的 onChanged 方法被調(diào)用。
Room 工作原理
- 抽象層封裝:Room 提供了一個(gè)抽象層,開發(fā)者通過(guò)定義實(shí)體類(使用
@Entity注解)、數(shù)據(jù)訪問(wèn)對(duì)象(DAO,使用@Dao注解)和數(shù)據(jù)庫(kù)類(使用@Database注解)來(lái)描述數(shù)據(jù)庫(kù)結(jié)構(gòu)和操作。實(shí)體類對(duì)應(yīng)數(shù)據(jù)庫(kù)表,DAO 定義了對(duì)數(shù)據(jù)庫(kù)的增刪改查操作,數(shù)據(jù)庫(kù)類則管理數(shù)據(jù)庫(kù)的版本和 DAO 實(shí)例。 - 編譯時(shí)處理:在編譯時(shí),Room 會(huì)根據(jù)開發(fā)者定義的注解生成相應(yīng)的 SQLite 語(yǔ)句和實(shí)現(xiàn)代碼。這樣可以在編譯階段就發(fā)現(xiàn)數(shù)據(jù)庫(kù)操作中的錯(cuò)誤,提高開發(fā)效率和代碼的健壯性。
- 線程管理:Room 默認(rèn)不允許在主線程中執(zhí)行數(shù)據(jù)庫(kù)操作,因?yàn)閿?shù)據(jù)庫(kù)操作通常是耗時(shí)的,可能會(huì)導(dǎo)致 UI 卡頓。因此,Room 會(huì)將數(shù)據(jù)庫(kù)操作放在后臺(tái)線程中執(zhí)行,開發(fā)者可以使用
suspend函數(shù)(在 Kotlin 中)或自定義線程池來(lái)處理異步操作。
Room 通過(guò)注解定義數(shù)據(jù)庫(kù)結(jié)構(gòu)和操作,編譯時(shí)生成 SQL 語(yǔ)句和實(shí)現(xiàn)代碼,默認(rèn)在后臺(tái)線程執(zhí)行操作。
// 定義實(shí)體類
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>
}
// 定義數(shù)據(jù)庫(kù)類
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()
// 處理獲取到的新聞列表
}
}
}編譯時(shí),Room 會(huì)根據(jù) @Entity、@Dao 和 @Database 注解生成操作數(shù)據(jù)庫(kù)的 SQL 語(yǔ)句和實(shí)現(xiàn)代碼,suspend 函數(shù)保證數(shù)據(jù)庫(kù)操作在后臺(tái)線程執(zhí)行。
Navigation 工作原理
- 導(dǎo)航圖定義:開發(fā)者通過(guò) XML 文件定義導(dǎo)航圖,導(dǎo)航圖中包含了應(yīng)用的所有目的地(如
Fragment)、動(dòng)作(用于在目的地之間導(dǎo)航)和參數(shù)傳遞規(guī)則。每個(gè)目的地都有唯一的標(biāo)識(shí)符,動(dòng)作則定義了從一個(gè)目的地到另一個(gè)目的地的導(dǎo)航路徑。 - 導(dǎo)航控制器管理:
NavController是 Navigation 組件的核心,負(fù)責(zé)管理導(dǎo)航操作。它會(huì)根據(jù)導(dǎo)航圖中的定義,處理目的地之間的切換和參數(shù)傳遞。在Activity或Fragment中,可以通過(guò)findNavController方法獲取NavController實(shí)例,然后調(diào)用其navigate方法進(jìn)行導(dǎo)航。 - Back Stack 管理:
NavController維護(hù)了一個(gè)返回棧(Back Stack),用于記錄導(dǎo)航歷史。當(dāng)用戶點(diǎn)擊返回按鈕時(shí),NavController會(huì)從返回棧中彈出上一個(gè)目的地,實(shí)現(xiàn)返回操作。開發(fā)者可以通過(guò)配置導(dǎo)航圖中的popUpTo和popUpToInclusive屬性來(lái)控制返回棧的行為。
Navigation 通過(guò)導(dǎo)航圖定義目的地和動(dòng)作,NavController 管理導(dǎo)航和返回棧。
<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 中設(shè)置導(dǎo)航宿主
<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 中進(jìn)行導(dǎo)航
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 {
// 導(dǎo)航到 SecondFragment
findNavController().navigate(R.id.action_firstFragment_to_secondFragment)
}
return view
}
} NavController 根據(jù)導(dǎo)航圖中的定義,處理從 FirstFragment 到 SecondFragment 的導(dǎo)航,同時(shí)管理返回棧以支持返回操作。
總結(jié):
ViewModel 通過(guò) ViewModelStore 管理 UI 數(shù)據(jù)并在配置變更時(shí)保持狀態(tài),LiveData 實(shí)現(xiàn)生命周期感知的可觀察數(shù)據(jù)更新,Room 作為 SQLite ORM 自動(dòng)生成數(shù)據(jù)庫(kù)操作代碼并處理線程,Navigation 利用導(dǎo)航圖和 NavController 管理多 Fragment 導(dǎo)航,共同構(gòu)建響應(yīng)式、可維護(hù)的 Android 應(yīng)用架構(gòu)。
到此這篇關(guān)于kotlin中的模塊化結(jié)構(gòu)組件的文章就介紹到這了,更多相關(guān)kotlin模塊化結(jié)構(gòu)組件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android?掃碼槍輸入時(shí)屏蔽軟鍵盤和頂部狀態(tài)欄的解決方案
在Android設(shè)備上,使用掃碼槍時(shí)常遇到軟鍵盤和頂部狀態(tài)欄顯示問(wèn)題,本文介紹了在Android 7.1.2版本上,如何通過(guò)設(shè)置inputType為none屏蔽軟鍵盤,以及通過(guò)hideStatusBar和NoActionBar方法隱藏頂部狀態(tài)欄,以優(yōu)化掃碼槍使用界面,這些方法有助于提升使用掃碼槍場(chǎng)景的用戶體驗(yàn)2024-10-10
自己實(shí)現(xiàn)Android View布局流程
這篇文章主要介紹了自己實(shí)現(xiàn)Android View布局流程,幫助大家更好的理解和學(xué)習(xí)使用Android,感興趣的朋友可以了解下2021-03-03
XrecyclerView實(shí)現(xiàn)加載數(shù)據(jù)和切換不同布局
這篇文章主要為大家詳細(xì)介紹了XrecyclerView實(shí)現(xiàn)加載數(shù)據(jù)、切換不同布局功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-12-12
Android使用ftp方式實(shí)現(xiàn)文件上傳和下載功能
這篇文章主要介紹了Android使用ftp方式實(shí)現(xiàn)文件上傳和下載功能,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-06-06
Android 接收推送消息跳轉(zhuǎn)到指定頁(yè)面的方法
這篇文章主要介紹了Android 接收推送消息跳轉(zhuǎn)到指定頁(yè)面的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-01-01
Android 桌面快捷方式實(shí)現(xiàn)實(shí)例詳解
這篇文章主要為大家介紹了Android 桌面快捷方式實(shí)現(xiàn)實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11
android 關(guān)于利用簽名的SHA1進(jìn)行安全校驗(yàn)的方法之一(推薦)
下面小編就為大家?guī)?lái)一篇android 關(guān)于利用簽名的SHA1進(jìn)行安全校驗(yàn)的方法之一(推薦)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-01-01

