如何使用Koin DI在Activity之间共享ViewModel的相同实例?

时间:2019-07-17 14:03:48

标签: android kotlin dependency-injection koin

我正在Kotlin中使用Koin库进行DI

Koin提供by viewmodel()用于获取ViewModel by sharedViewModel()的实例,以获取片段中的相同实例。

如何在活动中获取相同的ViewModel实例?我没有找到任何方法来实现这一目标。

4 个答案:

答案 0 :(得分:3)

您必须在模块声明中使用viewModel{}而不是single { SharedViewModel() }

private val viewModel: SharedViewModel by viewModel()

而且,您可以在视图中使用viewModel()。

View1

private val viewModel: SharedViewModel by viewModel()

View2

loadKoinModules(module1)

但是您必须在视图开始时加载模块

unloadKoinModules(mainModule)

重要的一点是,必须在销毁视图时在其中卸载模块。

package main

import (
    "bufio"
    "fmt"
    "io"
    "log"
    "os/exec"
)

func main() {
    cmd := exec.Command("sh", "-c",
        `for i in $(seq 1 10000); do
          echo  '{"Name": "Bob", "Age": 32}'
          sleep $(( ${RANDOM}%5))            # <<<< Stops before reading all lines when uncommented
        done`,
    )
    stdout, err := cmd.StdoutPipe()
    if err != nil {
        log.Fatal(err)
    }

    if err := cmd.Start(); err != nil {
        log.Fatal(err)
    }

    printOutput(stdout)

    if err := cmd.Wait(); err != nil {
        log.Fatal(err)
    }

}

func printOutput(r io.Reader) {
    scanner := bufio.NewScanner(r)
    var x = 1
    for scanner.Scan() {
        fmt.Println(x, scanner.Text())
        x++
    }
    if err := scanner.Err(); err != nil {
        fmt.Println("reading input:", err)
    }
}

因此,当卸载模块时,您的单例ViewModel将被破坏。

答案 1 :(得分:0)

您需要阅读有关ViewModel的更多信息才能更好地理解它。 https://developer.android.com/topic/libraries/architecture/viewmodel

ViewModel已连接到您的Activity

因此您只能在他的ViewModel之间共享您的活动Fragments

这就是sharedViewModel中的koin

sharedViewModel是相同的,如果您将ViewModel Factory与相同的context一起使用。

Activities之间共享任何数据都可以通过Intent完成,Android中没有其他方法,

或者您可以保留一些static / global数据并在Activities

之间共享

答案 2 :(得分:0)

在对体系结构级别进行了一些研究或讨论之后,还报告并发布了github Koin,我找到了解决方案 在这种情况下,我们应该将该状态/数据保存到存储库中,我们需要在不在ViewModel中的多个活动之间共享该状态/数据,并且两个或多个不同的ViewModel可以访问保存在存储库单个实例中的相同状态/数据

see here

答案 3 :(得分:0)

我建议将应用程序设为ViewModelStoreOwner,并以应用程序所有者的身份注入viewModels。 所需的代码如下:

class App : Application(), ViewModelStoreOwner {
    private val mViewModelStore = ViewModelStore()

    override fun getViewModelStore(): ViewModelStore {
        return mViewModelStore
    }
}

您可以定义一些扩展以轻松注入viewModels


val Context.app: App
    get() = applicationContext as App

inline fun <reified T : ViewModel> Context.appViewModel(
    qualifier: Qualifier? = null,
    noinline state: BundleDefinition? = null,
    noinline parameters: ParametersDefinition? = null
): Lazy<T> {
    return lazy(LazyThreadSafetyMode.NONE) {
        GlobalContext.get().getViewModel(qualifier, state, { ViewModelOwner.from(app, null) }, T::class, parameters)
    }
}

inline fun <reified T : ViewModel> Fragment.appViewModel(
    qualifier: Qualifier? = null,
    noinline state: BundleDefinition? = null,
    noinline parameters: ParametersDefinition? = null
): Lazy<T> {
    return lazy(LazyThreadSafetyMode.NONE) {
        GlobalContext.get().getViewModel(qualifier, state, { ViewModelOwner.from(requireContext().app, null) }, T::class, parameters)
    }
}

然后您可以像这样注入viewModel

class MainActivity : AppCompatActivity() {
    private val mAppViewModel: AppViewModel by appViewModel()
}

该解决方案的优势在于您无需重新创建视图模型,并且如果您决定保存应用程序重启之间的状态,则可以轻松地将应用程序设置为SavedStateRegistryOwner,并使用{ {1}}从viewModel内部保存/恢复状态,现在已绑定到流程生命周期。