AndroidX ViewModel, एक ब्रिज की तरह काम करता है. यह आपके शेयर किए गए कारोबारी नियमों और यूज़र इंटरफ़ेस (यूआई) कॉम्पोनेंट के बीच एक साफ़ तौर पर कानूनी समझौता करता है. इस पैटर्न से यह पक्का करने में मदद मिलती है कि सभी प्लैटफ़ॉर्म पर डेटा एक जैसा हो. साथ ही, इससे हर प्लैटफ़ॉर्म के यूज़र इंटरफ़ेस (यूआई) को उसकी खास पहचान के हिसाब से पसंद के मुताबिक बनाया जा सकता है. Android पर Jetpack Compose और iOS पर SwiftUI का इस्तेमाल करके, यूज़र इंटरफ़ेस (यूआई) को डेवलप किया जा सकता है.
ViewModel इस्तेमाल करने के फ़ायदों और सभी सुविधाओं के बारे में ज़्यादा जानने के लिए, ViewModel का मुख्य दस्तावेज़ पढ़ें.
डिपेंडेंसी सेट अप करना
अपने प्रोजेक्ट में KMP ViewModel सेट अप करने के लिए, libs.versions.toml
फ़ाइल में डिपेंडेंसी तय करें:
[versions]
androidx-viewmodel = 2.9.3
[libraries]
androidx-lifecycle-viewmodel = { module = "androidx.lifecycle:lifecycle-viewmodel", version.ref = "androidx-viewmodel" }
इसके बाद, अपने केएमपी मॉड्यूल की build.gradle.kts
फ़ाइल में आर्टफ़ैक्ट जोड़ें और डिपेंडेंसी को api
के तौर पर एलान करें. ऐसा इसलिए, क्योंकि इस डिपेंडेंसी को बाइनरी फ़्रेमवर्क में एक्सपोर्ट किया जाएगा:
// You need the "api" dependency declaration here if you want better access to the classes from Swift code.
commonMain.dependencies {
api(libs.androidx.lifecycle.viewmodel)
}
Swift से ऐक्सेस करने के लिए, ViewModel API एक्सपोर्ट करें
डिफ़ॉल्ट रूप से, कोडबेस में जोड़ी गई कोई भी लाइब्रेरी, बाइनरी फ़्रेमवर्क में अपने-आप एक्सपोर्ट नहीं होगी. अगर एपीआई एक्सपोर्ट नहीं किए जाते हैं, तो वे बाइनरी फ़्रेमवर्क से सिर्फ़ तब उपलब्ध होते हैं, जब उन्हें शेयर किए गए कोड (iosMain
या commonMain
सोर्स सेट से) में इस्तेमाल किया जाता है. ऐसे में, एपीआई में पैकेज प्रीफ़िक्स शामिल होगा. उदाहरण के लिए, ViewModel
क्लास Lifecycle_viewmodelViewModel
क्लास के तौर पर उपलब्ध होगी. डिपेंडेंसी एक्सपोर्ट करने के बारे में ज़्यादा जानने के लिए, डिपेंडेंसी को बाइनरी में एक्सपोर्ट करना लेख पढ़ें.
उपयोगकर्ता अनुभव को बेहतर बनाने के लिए, ViewModel डिपेंडेंसी को बाइनरी फ़्रेमवर्क में एक्सपोर्ट किया जा सकता है. इसके लिए, build.gradle.kts
फ़ाइल में export
सेटअप का इस्तेमाल करें. इस फ़ाइल में, iOS बाइनरी फ़्रेमवर्क को तय किया जाता है. इससे ViewModel API को Swift कोड से सीधे तौर पर ऐक्सेस किया जा सकता है. ऐसा Kotlin कोड से भी किया जा सकता है:
listOf(
iosX64(),
iosArm64(),
iosSimulatorArm64(),
).forEach {
it.binaries.framework {
// Add this line to all the targets you want to export this dependency
export(libs.androidx.lifecycle.viewmodel)
baseName = "shared"
}
}
(ज़रूरी नहीं) JVM Desktop पर viewModelScope
का इस्तेमाल करना
ViewModel में कोरूटीन चलाने पर, viewModelScope
प्रॉपर्टी Dispatchers.Main.immediate
से जुड़ी होती है. यह हो सकता है कि डेस्कटॉप पर डिफ़ॉल्ट रूप से उपलब्ध न हो. इसे सही तरीके से काम करने के लिए, अपने प्रोजेक्ट में kotlinx-coroutines-swing
डिपेंडेंसी जोड़ें:
// Optional if you use JVM Desktop
desktopMain.dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-swing:[KotlinX Coroutines version]")
}
ज़्यादा जानकारी के लिए, Dispatchers.Main
दस्तावेज़ देखें.
commonMain
या androidMain
से ViewModel इस्तेमाल करना
शेयर किए गए commonMain
में ViewModel क्लास का इस्तेमाल करने के लिए, कोई खास शर्त नहीं है. साथ ही, androidMain
sourceSet में भी इसका इस्तेमाल करने के लिए कोई शर्त नहीं है. आपको सिर्फ़ इस बात का ध्यान रखना है कि किसी प्लैटफ़ॉर्म के लिए बने एपीआई का इस्तेमाल न किया जाए. साथ ही, आपको उन्हें अलग करना होगा. उदाहरण के लिए, अगर Android Application
का इस्तेमाल ViewModel कंस्ट्रक्टर पैरामीटर के तौर पर किया जा रहा है, तो आपको इस एपीआई से माइग्रेट करना होगा. इसके लिए, आपको इसे ऐब्स्ट्रैक्ट करना होगा.
प्लैटफ़ॉर्म के हिसाब से कोड इस्तेमाल करने के तरीके के बारे में ज़्यादा जानकारी यहां उपलब्ध है: Kotlin Multiplatform में प्लैटफ़ॉर्म के हिसाब से कोड लिखना.
उदाहरण के लिए, यहां दिए गए स्निपेट में, फ़ैक्ट्री के साथ ViewModel क्लास दी गई है. इसे commonMain
में तय किया गया है:
// commonMain/MainViewModel.kt class MainViewModel( private val repository: DataRepository, ) : ViewModel() { /* some logic */ } // ViewModelFactory that retrieves the data repository for your app. val mainViewModelFactory = viewModelFactory { initializer { MainViewModel(repository = getDataRepository()) } } fun getDataRepository(): DataRepository = DataRepository()
इसके बाद, यूज़र इंटरफ़ेस (यूआई) के कोड में, ViewModel को पहले की तरह वापस लाया जा सकता है:
// androidApp/ui/MainScreen.kt @Composable fun MainScreen( viewModel: MainViewModel = viewModel( factory = mainViewModelFactory, ), ) { // observe the viewModel state }
SwiftUI से ViewModel का इस्तेमाल करना
Android पर, ViewModel का लाइफ़साइकल अपने-आप मैनेज होता है. साथ ही, इसे ComponentActivity
, Fragment
, NavBackStackEntry
(Navigation 2) या rememberViewModelStoreNavEntryDecorator
(Navigation 3) के स्कोप में रखा जाता है. हालांकि, iOS पर SwiftUI में AndroidX ViewModel के बराबर कोई बिल्ट-इन सुविधा नहीं है.
ViewModel को अपने SwiftUI ऐप्लिकेशन के साथ शेयर करने के लिए, आपको कुछ सेटअप कोड जोड़ना होगा.
जेनेरिक के लिए फ़ंक्शन बनाना
Android पर, सामान्य ViewModel इंस्टेंस को इंस्टैंशिएट करने के लिए, क्लास रेफ़रंस रिफ़्लेक्शन सुविधा का इस्तेमाल किया जाता है. Objective-C जेनेरिक, Kotlin या Swift की सभी सुविधाओं के साथ काम नहीं करते. इसलिए, Swift से सीधे तौर पर जेनेरिक टाइप का ViewModel नहीं पाया जा सकता.
इस समस्या को हल करने के लिए, एक हेल्पर फ़ंक्शन बनाया जा सकता है. यह फ़ंक्शन, जेनेरिक टाइप के बजाय ObjCClass
का इस्तेमाल करेगा. इसके बाद, इंस्टैंशिएट करने के लिए ViewModel क्लास को वापस पाने के लिए, getOriginalKotlinClass
का इस्तेमाल करेगा:
// iosMain/ViewModelResolver.ios.kt /** * This function allows retrieving any ViewModel from Swift Code with generics. We only get * [ObjCClass] type for the [modelClass], because the interop between Kotlin and Swift code * doesn't preserve the generic class, but we can retrieve the original KClass in Kotlin. */ @BetaInteropApi @Throws(IllegalArgumentException::class) fun ViewModelStore.resolveViewModel( modelClass: ObjCClass, factory: ViewModelProvider.Factory, key: String?, extras: CreationExtras? = null, ): ViewModel { @Suppress("UNCHECKED_CAST") val vmClass = getOriginalKotlinClass(modelClass) as? KClass<ViewModel> require(vmClass != null) { "The modelClass parameter must be a ViewModel type." } val provider = ViewModelProvider.Companion.create(this, factory, extras ?: CreationExtras.Empty) return key?.let { provider[key, vmClass] } ?: provider[vmClass] }
इसके बाद, जब आपको Swift से फ़ंक्शन कॉल करना हो, तब T : ViewModel
टाइप का सामान्य फ़ंक्शन लिखा जा सकता है. साथ ही, T.self
का इस्तेमाल किया जा सकता है. इससे ObjCClass
को resolveViewModel
फ़ंक्शन में पास किया जा सकता है.
ViewModel स्कोप को SwiftUI लाइफ़साइकल से कनेक्ट करना
अगला चरण, एक IosViewModelStoreOwner
बनाना है. यह ObservableObject
और ViewModelStoreOwner
इंटरफ़ेस (प्रोटोकॉल) लागू करता है. ObservableObject
का इस्तेमाल इसलिए किया जाता है, ताकि इस क्लास को SwiftUI कोड में @StateObject
के तौर पर इस्तेमाल किया जा सके:
// iosApp/IosViewModelStoreOwner.swift class IosViewModelStoreOwner: ObservableObject, ViewModelStoreOwner { let viewModelStore = ViewModelStore() /// This function allows retrieving the androidx ViewModel from the store. /// It uses the utilify function to pass the generic type T to shared code func viewModel<T: ViewModel>( key: String? = nil, factory: ViewModelProviderFactory, extras: CreationExtras? = nil ) -> T { do { return try viewModelStore.resolveViewModel( modelClass: T.self, factory: factory, key: key, extras: extras ) as! T } catch { fatalError("Failed to create ViewModel of type \(T.self)") } } /// This is called when this class is used as a `@StateObject` deinit { viewModelStore.clear() } }
इस मालिक की मदद से, Android की तरह ही कई ViewModel टाइप वापस पाए जा सकते हैं.
IosViewModelStoreOwner
का इस्तेमाल करने वाली स्क्रीन के बंद होने और deinit
को कॉल करने पर, उन ViewModels की लाइफ़साइकल बंद हो जाती है. आधिकारिक दस्तावेज़ में जाकर, डीइनिशियलाइज़ेशन के बारे में ज़्यादा जानें.
इस समय, IosViewModelStoreOwner
को SwiftUI व्यू में @StateObject
के तौर पर इंस्टैंशिएट किया जा सकता है. साथ ही, ViewModel को वापस पाने के लिए viewModel
फ़ंक्शन को कॉल किया जा सकता है:
// iosApp/ContentView.swift struct ContentView: View { /// Use the store owner as a StateObject to allow retrieving ViewModels and scoping it to this screen. @StateObject private var viewModelStoreOwner = IosViewModelStoreOwner() var body: some View { /// Retrieves the `MainViewModel` instance using the `viewModelStoreOwner`. /// The `MainViewModel.Factory` and `creationExtras` are provided to enable dependency injection /// and proper initialization of the ViewModel with its required `AppContainer`. let mainViewModel: MainViewModel = viewModelStoreOwner.viewModel( factory: MainViewModelKt.mainViewModelFactory ) // ... // .. the rest of the SwiftUI code } }
Kotlin Multiplatform में उपलब्ध नहीं है
Android पर उपलब्ध कुछ एपीआई, Kotlin Multiplatform में उपलब्ध नहीं हैं.
Hilt के साथ इंटिग्रेशन
Hilt, Kotlin Multiplatform प्रोजेक्ट के लिए उपलब्ध नहीं है. इसलिए, commonMain
sourceSet में @HiltViewModel
एनोटेशन के साथ ViewModels का सीधे तौर पर इस्तेमाल नहीं किया जा सकता. ऐसे में, आपको किसी दूसरे DI फ़्रेमवर्क का इस्तेमाल करना होगा. जैसे, Koin, kotlin-inject, Metro या Kodein. Kotlin Multiplatform के साथ काम करने वाले सभी DI फ़्रेमवर्क, klibs.io पर देखे जा सकते हैं.
SwiftUI में फ़्लो देखना
SwiftUI में कोराउटीन फ़्लो को सीधे तौर पर मॉनिटर नहीं किया जा सकता. हालांकि, इस सुविधा को चालू करने के लिए, KMP-NativeCoroutines या SKIE लाइब्रेरी का इस्तेमाल किया जा सकता है.