AndroidX ViewModel, एक ब्रिज की तरह काम करता है. यह आपके शेयर किए गए कारोबारी नियम और यूज़र इंटरफ़ेस (यूआई) कॉम्पोनेंट के बीच एक साफ़ समझौता तय करता है. इस पैटर्न से, सभी प्लैटफ़ॉर्म पर डेटा को एक जैसा बनाए रखने में मदद मिलती है. साथ ही, हर प्लैटफ़ॉर्म के हिसाब से यूज़र इंटरफ़ेस (यूआई) को पसंद के मुताबिक बनाया जा सकता है. Android पर Jetpack Compose और iOS पर SwiftUI का इस्तेमाल करके, यूज़र इंटरफ़ेस (यूआई) को डेवलप करना जारी रखा जा सकता है.
ViewModel का इस्तेमाल करने के फ़ायदों और इसकी सभी सुविधाओं के बारे में ज़्यादा जानने के लिए, ViewModel का मुख्य दस्तावेज़ पढ़ें.
डिपेंडेंसी सेट अप करना
अपने प्रोजेक्ट में केएमपी ViewModel सेट अप करने के लिए, libs.versions.toml फ़ाइल में डिपेंडेंसी तय करें:
[versions]
androidx-viewmodel = 2.11.0
[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 एपीआई एक्सपोर्ट करना
डिफ़ॉल्ट रूप से, आपके कोड बेस में जोड़ी गई कोई भी लाइब्रेरी, बाइनरी फ़्रेमवर्क में अपने-आप एक्सपोर्ट नहीं होगी. अगर एपीआई एक्सपोर्ट नहीं किए जाते हैं, तो वे बाइनरी फ़्रेमवर्क से सिर्फ़ तब उपलब्ध होते हैं, जब उन्हें शेयर किए गए कोड (iosMain या commonMain सोर्स सेट से) में इस्तेमाल किया जाता है. ऐसे में, एपीआई में पैकेज प्रीफ़िक्स शामिल होगा. उदाहरण के लिए, ViewModel क्लास, Lifecycle_viewmodelViewModel क्लास के तौर पर उपलब्ध होगी. डिपेंडेंसी एक्सपोर्ट करने के बारे में ज़्यादा जानने के लिए, बाइनरी में डिपेंडेंसी एक्सपोर्ट करना लेख पढ़ें.
अनुभव को बेहतर बनाने के लिए, ViewModel डिपेंडेंसी को बाइनरी फ़्रेमवर्क में एक्सपोर्ट किया जा सकता है. इसके लिए, build.gradle.kts फ़ाइल में export सेटअप का इस्तेमाल करें. इस फ़ाइल में, iOS बाइनरी फ़्रेमवर्क को तय किया जाता है. इससे ViewModel एपीआई को 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"
}
}
(ज़रूरी नहीं) जेवीएम डेस्कटॉप पर 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 या androidMain sourceSet में ViewModel क्लास का इस्तेमाल करने के लिए, कोई खास शर्त नहीं है. सिर्फ़ एक बात का ध्यान रखना है कि किसी प्लैटफ़ॉर्म के लिए बने एपीआई का इस्तेमाल नहीं किया जा सकता. आपको उन्हें ऐब्स्ट्रैक्ट करना होगा. उदाहरण के लिए, अगर ViewModel कंस्ट्रक्टर पैरामीटर के तौर पर Android Application का इस्तेमाल किया जा रहा है, तो आपको इस एपीआई को ऐब्स्ट्रैक्ट करके, इससे माइग्रेट करना होगा.
प्लैटफ़ॉर्म के हिसाब से कोड इस्तेमाल करने के तरीके के बारे में ज़्यादा जानकारी, 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 ऐप्लिकेशन के साथ शेयर करने के लिए, आपको कुछ सेटअप कोड जोड़ना होगा.
जेनेरिक के साथ मदद करने के लिए फ़ंक्शन बनाना
जेनरिक ViewModel इंस्टेंस को इंस्टैंशिएट करने के लिए, Android पर क्लास रेफ़रंस रिफ़्लेक्शन सुविधा का इस्तेमाल किया जाता है. 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 की लाइफ़साइकल मिटा दी जाती है. आधिकारिक दस्तावेज़ में जाकर, डी-इनिशलाइज़ेशन के बारे में ज़्यादा जानें.
इस समय, SwiftUI व्यू में IosViewModelStoreOwner को @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 के साथ इंटिग्रेशन
Kotlin Multiplatform प्रोजेक्ट के लिए Hilt उपलब्ध नहीं है. इसलिए, commonMain sourceSet में @HiltViewModel एनोटेशन के साथ ViewModels का इस्तेमाल सीधे तौर पर नहीं किया जा सकता. ऐसे में, आपको किसी अन्य डीआई फ़्रेमवर्क का इस्तेमाल करना होगा. उदाहरण के लिए, Koin, kotlin-inject, Metro या Kodein. Kotlin Multiplatform के साथ काम करने वाले सभी डीआई फ़्रेमवर्क, klibs.io पर देखे जा सकते हैं.
SwiftUI में फ़्लो को मॉनिटर करना
SwiftUI में, कोरूटीन फ़्लो को सीधे तौर पर मॉनिटर नहीं किया जा सकता. हालांकि, इस सुविधा को चालू करने के लिए, KMP-NativeCoroutines या SKIE लाइब्रेरी का इस्तेमाल किया जा सकता है.