Skip to content

Instantly share code, notes, and snippets.

@kevivforever
Last active August 17, 2019 05:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kevivforever/1264571ff31e591a8c71011404e1f524 to your computer and use it in GitHub Desktop.
Save kevivforever/1264571ff31e591a8c71011404e1f524 to your computer and use it in GitHub Desktop.
View Models
class DoubleLiveData<A, B>(a: LiveData<A>, b: LiveData<B>) : MediatorLiveData<Pair<A?, B?>>() {
init {
addSource(a) { value = it to b.value }
addSource(b) { value = a.value to it }
}
}
open class Event<out T>(private val content: T) {
private var hasBeenHandled = AtomicBoolean(false)
/**
* Returns the content and prevents its use again.
*/
fun getIfNotHandled(): T? = if (hasBeenHandled.getAndSet(true)) null else content
/**
* Returns the content, even if it's already been handled.
*/
fun peek(): T = content
}
class Resource<out T> private constructor(val status: Status, val data: T?) {
companion object {
fun <T> success(data: T? = null): Resource<T> = Resource(Status.SUCCESS, data)
fun <T> error(data: T? = null): Resource<T> = Resource(Status.ERROR, data)
fun <T> loading(data: T? = null): Resource<T> = Resource(Status.LOADING, data)
fun <T> unknown(data: T? = null): Resource<T> = Resource(Status.UNKNOWN, data)
}
}
// if you have two different data sources and want to see if both the request are complete
private val isUserDataFetched: LiveData<Boolean> =
Transformations.map(userLiveData) { it.status == Status.SUCCESS }
private val isPostDataFetched: LiveData<Boolean> =
Transformations.map(postLiveData) { it.status == Status.SUCCESS }
val isDataFetchComplete: LiveData<Boolean> = Transformations.map(DoubleLiveData(isUserDataFetched, isPostDataFetched)) {
it.first == it.second && it.first!! && it.second!!
}
class TripleLiveData<A, B, C>(first: LiveData<A>, second: LiveData<B>, third: LiveData<C>) : MediatorLiveData<Triple<A?, B?, C?>>() {
init {
addSource(first) { value = Triple(it, second.value, third.value) }
addSource(second) { value = Triple(first.value, it, third.value) }
addSource(third) { value = Triple(first.value, second.value, it) }
}
}
/**
* When ViewModel require parameters in the constructor then ViewModelProviders.of(activity).get(ViewModel.class) do not work
* In this case we need to provide our own ViewModelProvider's Factory.
* create method is called by Android Framework when it needs to create a ViewModel instance.
* NOTE: When activity rotates then create method is not called but earlier instance of ViewModel is returned.
* that is why creator is provided here so that Android Framework can create the ViewModel instance according to its need.
* @T: It says that the ViewModelProviderFactory works with variable of type SplashViewModel
* Example: T -> SplashViewModel,
*
*/
@Singleton
class ViewModelProviderFactory<T : ViewModel>(
private val kClass: KClass<T>, // KClass is the holder of class of type ViewModel that needs to be inject
private val creator: () -> T // This is the Lambda function, this is provided be the ActivityModule/FragmentModule,
// when creator lambda is called then that module creates and return the instance of ViewModel
) : ViewModelProvider.NewInstanceFactory() {
@Suppress("UNCHECKED_CAST")
@Throws(IllegalArgumentException::class)
override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(kClass.java)) return creator() as T
throw IllegalArgumentException("Unknown class name")
}
}
create new viewmodel using above viewmodelfactory
ViewModelProviders.of(activity , ViewModelProviderFactory(MainViewModel::class) {
MainViewModel(userPreferences, databaseService, compositeDisposable)
}).get(MainViewModel::class.java)
/**
* Step 1 create viewmdel without any parameters
*/
val vm: UserViewModel by lazy { ViewModelProviders.of(this).get(UserViewModel::class.java) }
/**
* Step 2 create viewmodel specific factory method to pass paramters
*/
class UserViewModelFactory(val userId: Int) : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return UserViewModel(userId) as T
}
}
val vm: UserViewModel by lazy {
ViewModelProviders.of(this, UserViewModelFactory(intent.getIntExtra(USER_ID, -1))).get(UserViewModel::class.java)
}
/**
* Step 3 create base factory method so that we dont have create separate factory method for each viewmodel
*/
class BaseViewModelFactory<T>(val creator: () -> T) : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return creator() as T
}
}
val vm: UserViewModel by lazy {
ViewModelProviders.of(this, BaseViewModelFactory { UserViewModel(intent.getIntExtra(USER_ID, -1)) }).get(UserViewModel::class.java)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment