Created
January 14, 2020 19:15
-
-
Save fnk0/5311ac8a82f28e49437dc610ee6dd446 to your computer and use it in GitHub Desktop.
Parent View Model with Contract Interface
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import androidx.annotation.MainThread | |
import androidx.fragment.app.Fragment | |
import kotlin.reflect.KClass | |
interface ViewModelContractProvider { | |
fun <T : Any> provideViewModelContract(clazz: KClass<T>): T | |
val supportedContracts: Set<KClass<*>> | |
} | |
/** | |
* Recursively searches parent fragments for it's ViewModelContractProvider | |
* If no ViewModelContractProvider is found on parent fragments it will retrieve it from the Activity | |
* If there is no ViewModelContractProvider in the scope of this fragment an IllegalArgumentException will be thrown | |
*/ | |
fun <T : Any> Fragment.findViewModelByContract(clazz: KClass<T>): T { | |
if (supportsViewModelContract(clazz)) { | |
return (this as ViewModelContractProvider).provideViewModelContract<T>(clazz) | |
} | |
// Note the version of fragment that arch components is using does not have the method | |
// requireParentFragment() so we store into a val | |
val parent = parentFragment | |
if (parent != null) { | |
return parent.findViewModelByContract<T>(clazz) | |
} | |
if (activity?.supportsViewModelContract(clazz) == true) { | |
return (requireActivity() as ViewModelContractProvider).provideViewModelContract<T>(clazz) | |
} | |
throw IllegalArgumentException("There is no ViewModelContractProvider associated with $this") | |
} | |
@MainThread | |
inline fun <reified T : Any> Fragment.viewModelContract(): Lazy<T> { | |
return lazy(LazyThreadSafetyMode.NONE) { | |
findViewModelByContract<T>(T::class) | |
} | |
} | |
private fun <T : Any> Any.supportsViewModelContract(clazz: KClass<T>): Boolean { | |
if (this is ViewModelContractProvider) { | |
return supportedContracts.contains(clazz) | |
} | |
return false | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class SomeActivity : AppCompatActivity(): ViewModelContractProvider { | |
override fun <T: Any> provideViewModelContract(): T { | |
@Suppress("UNCHECKED_CAST") val nullableVm = viewModel as? T | |
checkNotNull(nullableVm) { | |
"$viewModel does not implement required Contract" | |
} | |
return nullableVm | |
} | |
override val supportedContracts: Set<KClass<*>> = setOf(SomeViewModelContract::class) | |
} | |
class SomeActivityViewModel : ViewModel(): SomeViewModelContract {} | |
class SomeFragmentViewModel : ViewModel() {} | |
interface SomeFragmentViewModelContract { | |
} | |
class SomeFragment : Fragment() { | |
val myViewModel by viewModels<SomeFragmentViewModel>() | |
val contractViewModel by viewModelContract<SomeFragmentViewModelContract>() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment