Closed chachako closed 4 years ago
蛋疼啊,Scene 不想有 onConfigurationChanged 这些
蛋疼啊,Scene 不想有 onConfigurationChanged 这些
好的,那我手动改改吧...
你可以搞个子类实现这个接口,然后 onActivityCreateed 里面通过 NavigationScene.addConfigurationXXXX 的转发给自己的方法,其实我感觉 koin 的这个要求很奇怪
另外一种是自己写一个LifecycleOwner.getKoin()的扩展方法。然后通过getkoin().getViewModel(lifecycleowner....)手动实现一个viewmodl代理方法。
fun LifecycleOwner.getKoin(): Koin = when (this) {
is KoinComponent -> this.getKoin()
is Scene -> ((this as? KoinComponent)?.getKoin()
?: (this.requireActivity() as? KoinComponent)?.getKoin()
?: error("scene attach parent must be KoinComponent"))
else -> KoinContextHandler.get()
}
If you would like to use two frameworks together, you should define a new extension then you can use the koin framework with scene framework.
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.*
import com.bytedance.scene.Scene
import org.koin.android.viewmodel.*
import org.koin.core.Koin
import org.koin.core.context.GlobalContext
import org.koin.core.parameter.ParametersDefinition
import org.koin.core.qualifier.Qualifier
import org.koin.core.scope.Scope
import kotlin.reflect.KClass
inline fun <reified T : ViewModel> LifecycleOwner.customViewModel(
qualifier: Qualifier? = null,
noinline parameters: ParametersDefinition? = null
): Lazy<T> = lazy { getViewModelCustom(qualifier, parameters) }
inline fun <reified T : ViewModel> LifecycleOwner.getViewModelCustom(
qualifier: Qualifier? = null,
noinline parameters: ParametersDefinition? = null
): T {
return getViewModelCustom(T::class, qualifier, parameters)
}
fun <T : ViewModel> LifecycleOwner.getViewModelCustom(
clazz: KClass<T>,
qualifier: Qualifier? = null,
parameters: ParametersDefinition? = null
): T {
return GlobalContext.get().koin.getViewModelCustom(
ViewModelParameters(
clazz,
this@getViewModelCustom,
qualifier,
parameters = parameters
)
)
}
fun <T : ViewModel> Koin.getViewModelCustom(parameters: ViewModelParameters<T>): T {
val vmStore: ViewModelStore = parameters.owner.getViewModelStoreCustom(parameters)
val viewModelProvider = rootScope.createViewModelProviderCustom(vmStore, parameters)
return viewModelProvider.getInstanceCustom(parameters)
}
fun <T : ViewModel> ViewModelProvider.getInstanceCustom(parameters: ViewModelParameters<T>): T {
val javaClass = parameters.clazz.java
return if (parameters.qualifier != null) {
this.get(parameters.qualifier.toString(), javaClass)
} else {
this.get(javaClass)
}
}
fun <T : ViewModel> LifecycleOwner.getViewModelStoreCustom(
parameters: ViewModelParameters<T>
): ViewModelStore =
when {
parameters.from != null -> parameters.from!!.invoke().viewModelStore
this is FragmentActivity -> ViewModelStores.of(this)
this is Fragment -> ViewModelStores.of(this)
this is Scene -> this.viewModelStore
else -> error("Can't getByClass ViewModel '${parameters.clazz}' on $this - Is not a FragmentActivity nor a Fragment neither a valid ViewModelStoreOwner")
}
fun <T : ViewModel> Scope.createViewModelProviderCustom(
vmStore: ViewModelStore,
parameters: ViewModelParameters<T>
): ViewModelProvider {
return ViewModelProvider(
vmStore,
object : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return get(parameters.clazz, parameters.qualifier, parameters.parameters)
}
})
}
After you created the extension you can use like code shown below.
class SplashScene : Scene() {
private val splashViewModel: SplashViewModel by customViewModel()
}
i use koin version is 3.2.0,scene version is 1.3.1 i used code
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelStoreOwner
import com.bytedance.scene.Scene
import com.bytedance.scene.ktx.viewModels
import org.koin.android.scope.getScopeOrNull
import org.koin.androidx.viewmodel.ext.android.getViewModelFactory
import org.koin.core.annotation.KoinInternalApi
import org.koin.core.component.getScopeId
import org.koin.core.component.getScopeName
import org.koin.core.context.GlobalContext
import org.koin.core.parameter.ParametersDefinition
import org.koin.core.qualifier.Qualifier
@OptIn(KoinInternalApi::class)
inline fun <reified T : ViewModel> Scene.viewModel(
qualifier: Qualifier? = null,
owner : ViewModelStoreOwner = this,
noinline parameters: ParametersDefinition? = null
): Lazy<T> {
val scope = GlobalContext.get().createScope(getScopeId(), getScopeName())
val activityScope = activity?.getScopeOrNull()
activityScope?.let { scope.linkTo(it) }
return viewModels{
getViewModelFactory<T>(owner, qualifier, parameters, scope = scope)
}
}
after i used like code below
class DiscoverScene : AppCompatScene() {
private val model: DiscoverViewModel by viewModel()
}
在使用依赖注入框架 Koin 注入 ViewModel 时报 ClassCastException 异常,是否应该为 Scene 继承
ComponentCallbacks
接口https://github.com/bytedance/scene/blob/3dc15e1f2e5ce0acc662c65613475ee386341a24/library/scene/src/main/java/com/bytedance/scene/Scene.java#L112