AndroidX ViewModel একটি ব্রিজ হিসেবে কাজ করে, যা আপনার শেয়ার করা বিজনেস লজিক এবং আপনার UI কম্পোনেন্টের মধ্যে একটি স্পষ্ট চুক্তি স্থাপন করে। এই প্যাটার্নটি বিভিন্ন প্ল্যাটফর্ম জুড়ে ডেটা সামঞ্জস্য নিশ্চিত করতে সাহায্য করে, পাশাপাশি প্রতিটি প্ল্যাটফর্মের স্বতন্ত্র চেহারার জন্য UI কাস্টমাইজ করার সুবিধা দেয়। আপনি Android-এ Jetpack Compose এবং iOS-এ SwiftUI-এর মাধ্যমে UI ডেভেলপ করা চালিয়ে যেতে পারবেন।
ViewModel ব্যবহার করার সুবিধা এবং ViewModel-এর প্রাথমিক ডকুমেন্টেশনে থাকা সব ফিচার সম্পর্কে আরও জানুন।
ডিপেন্ডেন্সি সেট-আপ করা
আপনার প্রোজেক্টে KMP ViewModel সেট-আপ করতে, libs.versions.toml ফাইলে নির্ভরতা নির্ধারণ করুন:
[versions]
androidx-viewmodel = 2.11.0
[libraries]
androidx-lifecycle-viewmodel = { module = "androidx.lifecycle:lifecycle-viewmodel", version.ref = "androidx-viewmodel" }
তারপরে, আপনার KMP মডিউলের জন্য 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 এক্সপোর্ট করা
ডিফল্ট হিসেবে, আপনার কোডবেসে যোগ করা যেকোনও লাইব্রেরি বাইনারি ফ্রেমওয়ার্কে অটোমেটিক
এক্সপোর্ট করা হবে না। API এক্সপোর্ট করা না হলে, সেগুলি
বাইনারি ফ্রেমওয়ার্ক থেকে তখনই উপলভ্য হবে যদি আপনি সেগুলি শেয়ার করা কোডে
(iosMain বা commonMain সোর্স সেট থেকে) ব্যবহার করেন। সেই ক্ষেত্রে, API-তে প্যাকেজ প্রিফিক্স থাকবে, যেমন, ViewModel ক্লাসটি Lifecycle_viewmodelViewModel ক্লাস হিসেবে উপলভ্য হবে।
নির্ভরতা এক্সপোর্ট করা সম্পর্কে আরও জানতে, বাইনারিতে
নির্ভরতা এক্সপোর্ট করা দেখুন।
অভিজ্ঞতা উন্নত করতে, আপনি ViewModel নির্ভরতা বাইনারি
ফ্রেমওয়ার্কে এক্সপোর্ট করতে পারেন। এর জন্য export-এ সেট-আপ করুন build.gradle.kts ফাইল যেখানে আপনি
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 ডেস্কটপে 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 সোর্সসেটে ViewModel ক্লাস ব্যবহার করার জন্য কোনও নির্দিষ্ট প্রয়োজনীয়তা নেই। শুধুমাত্র এই বিষয়টি মাথায় রাখতে হবে যে
আপনি কোনও প্ল্যাটফর্ম-নির্দিষ্ট API ব্যবহার করতে পারবেন না এবং আপনাকে সেগুলি অ্যাবস্ট্রাক্ট করতে হবে। যেমন, আপনি যদি Android Application-কে ViewModel কনস্ট্রাক্টর
প্যারামিটার হিসেবে ব্যবহার করেন, তাহলে আপনাকে এটি অ্যাবস্ট্রাক্ট করে এই API থেকে মাইগ্রেট করতে হবে।
প্ল্যাটফর্ম-নির্দিষ্ট কোড কীভাবে ব্যবহার করতে হয় সেই সম্পর্কে আরও তথ্য 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()
তারপর, আপনার UI কোডে, আপনি স্বাভাবিকভাবে ViewModel রিট্রিভ করতে পারবেন:
// androidApp/ui/MainScreen.kt @Composable fun MainScreen( viewModel: MainViewModel = viewModel( factory = mainViewModelFactory, ), ) { // observe the viewModel state }
SwiftUI থেকে ViewModel ব্যবহার করা
Android-এ, ViewModel লাইফসাইকেল অটোমেটিক ম্যানেজ করা হয় এবং তা
ComponentActivity, Fragment, NavBackStackEntry (নেভিগেশন ২) অথবা
rememberViewModelStoreNavEntryDecorator (নেভিগেশন ৩)-এর মধ্যে সীমাবদ্ধ থাকে। iOS-এ SwiftUI-এর ক্ষেত্রে,
AndroidX ViewModel-এর সমতুল্য কোনও বিল্ট-ইন সুবিধা নেই।
আপনার SwiftUI অ্যাপের সাথে ViewModel শেয়ার করতে, আপনাকে কিছু সেট-আপ কোড যোগ করতে হবে।
জেনারেটিকের ব্যাপারে সাহায্য করতে একটি ফাংশন তৈরি করো
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 ফাংশনে
পাস করতে পারে।
SwiftUI লাইফসাইকেলে ViewModel স্কোপ কানেক্ট করা
পরবর্তী ধাপ হল এমন একটি 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 কল করা হলে, সেইসব ViewModel-এর লাইফসাইকেল মুছে যায়। আপনি
অফিসিয়াল ডকুমেন্টেশন থেকে
ডিনিশিয়ালাইজেশন সম্পর্কে আরও জানতে পারবেন।
এই পর্যায়ে, আপনি SwiftUI View-তে 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-এ উপলভ্য কিছু API Kotlin Multiplatform-এ উপলভ্য নেই।
Hilt-এর সাথে ইন্টিগ্রেশন
Kotlin Multiplatform প্রোজেক্টের জন্য Hilt উপলভ্য না থাকার কারণে,
commonMain sourceSet-এ @HiltViewModel অ্যানোটেশন সহ ViewModel সরাসরি ব্যবহার করতে পারবেন না। সেই ক্ষেত্রে, আপনাকে কিছু বিকল্প DI
ফ্রেমওয়ার্ক ব্যবহার করতে হবে, যেমন, Koin,
kotlin-inject, Metro, বা
Kodein. আপনি klibs.io লিঙ্কে Kotlin Multiplatform-এর সাথে কাজ করে এমন
সব DI ফ্রেমওয়ার্ক খুঁজে পাবেন।
SwiftUI-তে Flow পর্যবেক্ষণ করা
SwiftUI-তে কোরাউটিন ফ্লো সরাসরি পর্যবেক্ষণ করা যায় না। তবে, এই ফিচার চালু করতে আপনি KMP-NativeCoroutines অথবা SKIE লাইব্রেরি ব্যবহার করতে পারেন।