The modular structure components include ViewModel, LiveData, Room, and Navigation, and I will explain how they work and basic usage.
How ViewModel works
-
Creation and storage mechanisms: When called
ViewModelProvider
ofget
Method ObtainViewModel
When an instance,ViewModelProvider
Will check firstViewModelStore
Whether an instance of this type already exists in . If it exists, it will be returned directly, if it does not exist, it will be usedCreate a new instance and store it in
ViewModelStore
middle. EachActivity
andFragment
All have their own correspondingViewModelStore
, used to manage its internalViewModel
Example. -
Lifecycle Management:
ViewModel
Life cycle and relatedActivity
orFragment
Finally related, but also different. When configuration changes (such as screen rotation),Activity
orFragment
Will be recreated, andViewModelStore
Will be retained, soViewModel
Instances can also be retained to ensure data consistency. whenActivity
orFragment
When destroyed (not due to configuration changes),ViewModelStore
Will callclear
Method, then callViewModel
ofonCleared
Methods allow developers to perform resource release operations here.
ViewModel byViewModelStore
Store instances, retain data when configuration changes, and release resources when associated components are destroyed by non-configuration changes.
// Define the ViewModel classimport import class NewsViewModel : ViewModel() { // Define LiveData to store news list private val _newsList = MutableLiveData<List<String>>() val newsList: LiveData<List<String>> = _newsList init { // Simulate to obtain news data from the network or database fetchNews() } private fun fetchNews() { // This can be replaced by real network requests or database query val mockNews = listOf("News 1", "News 2", "News 3") _newsList.value = mockNews } } // Use ViewModel in Activityimport import import import .activity_main.* class MainActivity : AppCompatActivity() { private lateinit var newsViewModel: NewsViewModel override fun onCreate(savedInstanceState: Bundle?) { (savedInstanceState) setContentView{"name":"GodelPlugin","parameters":{"input":"\"setContentView(.activity_main)\""}}<|FunctionExecuteEnd|><|FunctionExecuteResult|>setContentView(.activity_main)<|FunctionExecuteResultEnd|> // Get the ViewModel instance newsViewModel = ViewModelProvider(this).get(NewsViewModel::) // Observe LiveData data changes (this, { news -> // Update UI { ("$it\n") } }) } }
When the configuration changes such as screen rotation,MainActivity
Recreate, butNewsViewModel
The instance will be fromViewModelStore
retrieve and the data can be retained.
How LiveData works
-
Data Holding and Observer Management:
LiveData
An internal data object and an observer list are maintained. When calledobserve
Method When registering an observer, theLifecycleOwner
andObserver
Packaged intoLifecycleBoundObserver
Object and add to the observer list. -
Life cycle perception:
LifecycleBoundObserver
ImplementedLifecycleEventObserver
Interface, able to monitorLifecycleOwner
life cycle changes. whenLifecycleOwner
Enter active state (STARTED
orRESUMED
)hour,LiveData
The latest data will be sent to the observer; whenLifecycleOwner
Enter destruction state (DESTROYED
)hour,LiveData
The observer will be automatically removed to avoid memory leakage. -
Data update notification: When called
setValue
(main thread) orpostValue
When the (child thread) method updates the data,LiveData
It will check the life cycle status of all observers, and only observers in active state will receive itonChanged
The call of the method, thereby updating the UI.
LiveData holds data, throughLifecycleBoundObserver
PerceptionLifecycleOwner
Life cycle, notifies the observer only when active.
import import import import import .activity_main.* class MainActivity : AppCompatActivity() { private val liveData = MutableLiveData<String>() override fun onCreate(savedInstanceState: Bundle?) { (savedInstanceState) setContentView{"name":"GodelPlugin","parameters":{"input":"\"setContentView(.activity_main)\""}}<|FunctionExecuteEnd|><|FunctionExecuteResult|>setContentView(.activity_main)<|FunctionExecuteResultEnd|> // Register an observer (this, Observer { data -> // Handle data changes = data }) // Update data = "New Data" } }
When registering,
this
(Right nowMainActivity
AsLifecycleOwner
)andObserver
Packaging, whenMainActivity
Active andliveData
When data is updated,Observer
ofonChanged
The method is called.
How Room Works
-
Abstract layer encapsulation: Room provides an abstraction layer, which developers define entity classes (using
@Entity
Annotation), data access object (DAO, use@Dao
Annotations) and database classes (using@Database
Annotation) to describe the database structure and operations. The entity class corresponds to the database table. DAO defines the operations of adding, deleting, modifying and checking the database. The database class manages the database version and DAO instance. - Compile-time processing: At compile time, Room will generate corresponding SQLite statements and implementation code based on the annotations defined by the developer. This way, errors in database operations can be found during the compilation stage, improving development efficiency and code robustness.
-
Thread management: Room does not allow database operations in the main thread by default, because database operations are usually time-consuming and may cause UI lag. Therefore, Room will place database operations in the background thread to execute, and developers can use
suspend
Functions (in Kotlin) or custom thread pools to handle asynchronous operations.
Room defines database structure and operations through annotations, generates SQL statements and implementation code during compilation, and performs operations in background threads by default.
// Define entity classimport import @Entity(tableName = "news") data class News( @PrimaryKey(autoGenerate = true) val id: Int = 0, val title: String ) // Define DAOimport import import @Dao interface NewsDao { @Insert suspend fun insertNews(news: News) @Query("SELECT * FROM news") suspend fun getAllNews(): List<News> } // Define database classimport import @Database(entities = [News::class], version = 1) abstract class AppDatabase : RoomDatabase() { abstract fun newsDao(): NewsDao } // Use Room in ViewModelimport import import class NewsViewModel : ViewModel() { private val database = ( applicationContext, AppDatabase::, "news-database" ).build() private val newsDao = () fun insertNews(news: News) { { (news) } } fun getAllNews() { { val newsList = () // Process the obtained news list } } }
When compiling, Room will use@Entity
、@Dao
and@Database
Annotation generates SQL statements and implementation code for operating databases,suspend
Functions ensure that database operations are executed in the background thread.
How Navigation works
-
Navigation diagram definition: The developer defines a navigation map through an XML file, which contains all the destinations of the application (such as
Fragment
), actions (used to navigate between destinations), and parameter passing rules. Each destination has a unique identifier, and the action defines the navigation path from one destination to another. -
Navigation Controller Management:
NavController
It is the core of the Navigation component and is responsible for managing navigation operations. It handles switching between destinations and parameter passing according to the definitions in the navigation diagram. existActivity
orFragment
, you can passfindNavController
Method ObtainNavController
Instance, then call itnavigate
Method for navigation. -
Back Stack Management:
NavController
A Back Stack is maintained for recording navigation history. When the user clicks the return button,NavController
The previous destination will be popped out from the return stack to implement the return operation. Developers can configure the navigation mappopUpTo
andpopUpToInclusive
Attributes to control the behavior of returning the stack.
Navigation defines destinations and actions through navigation maps,NavController
Manage navigation and return to the stack.
<navigation xmlns:andro xmlns:app="/apk/res-auto" android: app:startDestination="@id/firstFragment"> <fragment android: android:name="" android:label="First Fragment"> <action android: app:destination="@id/secondFragment" /> </fragment> <fragment android: android:name="" android:label="Second Fragment" /> </navigation>
Set up navigation hosts in Activity
< android: android:name="" android:layout_width="match_parent" android:layout_height="match_parent" app:defaultNavHost="true" app:navGraph="@navigation/navigation_graph" />
Navigate in Fragment
import import import import import import class FirstFragment : Fragment() { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { val view = (.fragment_first, container, false) <Button>().setOnClickListener { // Navigate to SecondFragment findNavController().navigate(.action_firstFragment_to_secondFragment) } return view } }
NavController
According to the definition in the navigation diagram, the processing is fromFirstFragment
arriveSecondFragment
navigation, while managing the return stack to support return operations.
Summarize:
ViewModel
passViewModelStore
Manage UI data and keep it state when configuration changes,LiveData
Implement life cycle-aware observable data updates,Room
As a SQLite ORM, it automatically generates database operation code and processes threads.Navigation
Use navigation maps andNavController
Manage multiple Fragment navigation and jointly build a responsive and maintainable Android application architecture.
This is the article about modular structure components in kotlin. For more related contents of modular structure components, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!