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