Skip to content

Instantly share code, notes, and snippets.

@Lamartio
Last active May 10, 2019 08:13
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 Lamartio/c90262590a97fec2c6b39791b104f4fa to your computer and use it in GitHub Desktop.
Save Lamartio/c90262590a97fec2c6b39791b104f4fa to your computer and use it in GitHub Desktop.
ViewModelFactory
/*
* Copyright 2019 Danny Lamarti
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class ViewModelFactory(block: Builder.() -> Unit = {}) : ViewModelProvider.NewInstanceFactory() {
private val viewModels = Builder()
.apply(block)
.viewModels
.toMap()
private var params = Params()
fun withParams(vararg params: Any?): ViewModelFactory =
also {
it.params = params.toList().let(::Params)
}
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel?> create(modelClass: Class<T>): T =
try {
viewModels[modelClass]
?.invoke(params) as T
?: super.create(modelClass)
} finally {
params = Params()
}
inner class Builder {
val viewModels = mutableMapOf<Class<*>, (Params) -> ViewModel>()
inline fun <reified T : ViewModel> viewModel(crossinline block: (params: Params) -> T) =
viewModels.set(T::class.java, { block(it) })
}
@Suppress("UNCHECKED_CAST")
data class Params(private val params: List<Any?> = emptyList()) {
operator fun <T> component1() = get<T>(0)
operator fun <T> component2() = get<T>(1)
operator fun <T> component3() = get<T>(2)
operator fun <T> component4() = get<T>(3)
operator fun <T> component5() = get<T>(4)
operator fun <T> component6() = get<T>(5)
operator fun <T> get(index: Int) = params[index] as T
}
interface Owner {
val factory: ViewModelFactory
}
}
/*
* Copyright 2019 Danny Lamarti
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProviders
class TestViewModel : ViewModel()
class ParameteredViewModel(val id: String) : ViewModel()
fun example(fragment: Fragment) {
val factory = ViewModelFactory {
viewModel { TestViewModel() }
viewModel { (id: String) -> ParameteredViewModel(id) } // Gets the id from the UI
}
val testViewModel: TestViewModel = ViewModelProviders
.of(fragment, factory)
.get(TestViewModel::class.java)
val parameteredViewModel: TestViewModel = ViewModelProviders
.of(fragment, factory.withParams("IDENTIFIER")) // UI passes the id argument
.get(TestViewModel::class.java)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment