package com.example.myapp.ui
import androidx.lifecycle.*
import kotlinx.coroutines.launch
class UserViewModel(
private val userRepository: UserRepository
) : ViewModel() {
private val _userId = MutableLiveData<Int>()
// Transform user ID to full user object
val user: LiveData<User?> = _userId.switchMap { id ->
liveData {
val user = userRepository.getUser(id)
emit(user)
}
}
// Map user to display name
val displayName: LiveData<String> = Transformations.map(user) { user ->
user?.let { "${it.firstName} ${it.lastName}" } ?: "Unknown"
}
// Combine multiple LiveData sources
private val _posts = MutableLiveData<List<Post>>()
private val _comments = MutableLiveData<List<Comment>>()
val feedItems: LiveData<FeedData> = MediatorLiveData<FeedData>().apply {
var posts: List<Post>? = null
var comments: List<Comment>? = null
fun update() {
if (posts != null && comments != null) {
value = FeedData(posts!!, comments!!)
}
}
addSource(_posts) { newPosts ->
posts = newPosts
update()
}
addSource(_comments) { newComments ->
comments = newComments
update()
}
}
// Conditional transformation
private val _searchQuery = MutableLiveData<String>()
val searchResults: LiveData<List<Post>> = _searchQuery.switchMap { query ->
if (query.isNullOrBlank()) {
liveData { emit(emptyList<Post>()) }
} else {
liveData {
val results = userRepository.searchPosts(query)
emit(results)
}
}
}
// Custom transformation with distinct
val postCount: LiveData<Int> = Transformations.distinctUntilChanged(
Transformations.map(_posts) { it?.size ?: 0 }
)
fun setUserId(id: Int) {
_userId.value = id
}
fun search(query: String) {
_searchQuery.value = query
}
}
data class FeedData(
val posts: List<Post>,
val comments: List<Comment>
)
LiveData transformations create derived data streams reactively. Transformations.map() converts values—like mapping User to username string. Transformations.switchMap() switches LiveData sources based on input, enabling dynamic queries. MediatorLiveData combines multiple LiveData sources, useful for aggregating data. The Mediator observes sources and updates when any changes. Transformations execute lazily only when observed. They maintain lifecycle awareness, preventing memory leaks. distinctUntilChanged() prevents duplicate emissions. These patterns eliminate manual observation management and enable declarative data flows. Transformations work with ViewModels to expose clean, transformed state to UI layers while keeping business logic separate.
Related snips
package com.example.myapp
import android.app.Application
import dagger.hilt.android.HiltAndroidApp
@HiltAndroidApp
Dependency injection with Hilt
package com.example.myapp.utils
import android.os.Build
import android.os.StrictMode
import android.os.Trace
import timber.log.Timber
Performance optimization and profiling
package com.example.myapp.widget
import android.app.PendingIntent
import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider
import android.content.Context
App widgets for home screen
package com.example.myapp.data.repository
import com.example.myapp.data.local.PostDao
import com.example.myapp.data.local.PostEntity
import com.example.myapp.data.remote.ApiService
import com.example.myapp.models.Post
Unit testing with JUnit and MockK
package com.example.myapp.utils
import android.app.NotificationChannel
import android.app.NotificationChannelGroup
import android.app.NotificationManager
import android.app.PendingIntent
Notification channels and categories
package com.example.myapp.data.remote
import com.squareup.moshi.Moshi
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
Retrofit for REST API networking
Share this code
Here's the card — post it anywhere.