Applying Kotlin Coroutines and Jetpack MVVM in Ctrip Flight App: Architecture, Implementation, and Production Challenges
This article explains how Ctrip's flight Android app refactored its home page using Kotlin coroutines, Jetpack AAC components, and MVVM architecture, detailing the technical and business background, code patterns, production issues, and lessons learned for large‑scale mobile development.
The author, a senior Ctrip ticket‑app engineer, introduces the technical background: since 2017 Kotlin has become the de‑facto language for Android, but coroutine adoption remains low despite its benefits such as simpler asynchronous code, easier task management, and efficient cold streams (Flow).
Business needs demanded a new platform‑wide search homepage for travel services. The team chose Android Jetpack AAC components and Kotlin coroutines to rebuild the flight app, targeting two common scenarios: multiple views sharing a data source and multiple views triggering the same data update.
Using MVVM, ViewModel holds shared state, LiveData exposes it, and Views (Fragments or custom Views) subscribe to the LiveData. The article shows a basic ViewModel implementation with a Channel<String> and a liveData { for (result in departCityTextChannel) emit(result) } pattern, and how viewModelScope.launch(Dispatchers.IO) updates the channel.
To reduce boilerplate, the author defines a top‑level function inline fun getViewModel(owner: ViewModelStoreOwner, configLiveData: T.() -> Unit = {}): T and an extension version inline fun ViewModelStoreOwner.getSelfViewModel(configLiveData: T.() -> Unit = {}): T , allowing concise ViewModel retrieval and LiveData subscription inside Fragments.
Further abstraction introduces an inline extension property inline val Channel .coroutineLiveData: LiveData that creates a LiveData from a Channel, simplifying repeated patterns.
The UI layer is illustrated with custom CityView and CityView2 classes that inflate layouts, expose an initObserver generic function to bind a shared ViewModel, and update UI via callbacks, demonstrating clean separation of View, ViewModel, and Model responsibilities.
Complex scenarios where multiple Views share and mutate the same data source are addressed, showing how the same ViewModel instance can be used across different Views by passing the same owner (Fragment or Activity) to initObserver .
Production challenges are discussed: integrating newer versions of kotlinx.coroutines caused INSTALL_FAILED_DEXOPT on some Android 5.x devices, and Dispatchers.Main crashes occurred sporadically. The team evaluated workarounds (SDK/Gradle upgrades, custom Dispatchers, forking the library) and ultimately settled on using version 1.3.0 with a temporary fork that back‑ported the 1.3.3 bug‑fix.
In conclusion, the author reflects on Kotlin’s maturity, the power of coroutines, and the stability of Jetpack components, while noting future migration plans toward newer Kotlin and Jetpack libraries such as Compose, Room, Hilt, and WorkManager.
Ctrip Technology
Official Ctrip Technology account, sharing and discussing growth.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.