Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 安卓,Can';t从分离的片段访问ViewModels_Android_Kotlin_Android Fragments_Mvvm_Koin - Fatal编程技术网

Android 安卓,Can';t从分离的片段访问ViewModels

Android 安卓,Can';t从分离的片段访问ViewModels,android,kotlin,android-fragments,mvvm,koin,Android,Kotlin,Android Fragments,Mvvm,Koin,每次我旋转手机时,它都会崩溃并在SearchResultFragment中打印奇怪的异常,无论isDetached值为false: java.lang.IllegalStateException: Can't access ViewModels from detached fragment 在本部分代码中: private val searchViewModel: SearchViewModel by viewModel() fun searchWord(word: String) {

每次我旋转手机时,它都会崩溃并在SearchResultFragment中打印奇怪的异常,无论
isDetached
值为false

java.lang.IllegalStateException: Can't access ViewModels from detached fragment
在本部分代码中:

private val searchViewModel: SearchViewModel by viewModel()

fun searchWord(word: String) {
        if(!isDetached) searchResultViewModel.searchWord(word)
}
从另一个片段SearchFragment调用:

searchResultFragment.searchWord(searchWord)
SearchResultFragment以以下方式添加到SearchFragment:

private val searchResultFragment = SearchResultFragment()

private fun addFragment() {
    val fragmentTransaction = childFragmentManager.beginTransaction()
    fragmentTransaction.add(R.id.searchContainer, searchResultFragment)
    fragmentTransaction.commit()
}

我正在使用Koin进行依赖注入。我将非常感谢所有提示。

如果没有完整的上下文,很难准确地看到发生了什么

我看到的#1问题(其他一些用户也提到)是,您似乎在从另一个片段调用片段中的公共方法。这是一个危险信号,因为您现在正在将两个独立于生命周期的对象相互耦合(除其他外)

如果说有什么区别的话,那么最快的解决办法就是您可以依赖一个共享视图模型,该模型可以与两个片段进行对话,并可以提供您想要的状态

在任何情况下,由于很难判断到底发生了什么,您可以在
onCreateView(…)
中尝试类似的方法

 if (savedInstanceState == null) {
            supportFragmentManager.commit {
                replace(
                    R.id.searchContainer,
                    SearchResultFragment.newInstance(),
                    SearchResultFragment::class.java.simpleName
                )
            }
        }
newInstance()
在SearchResultFragment中实现为:

    companion object {
        fun newInstance() = SearchResultFragment()
    }
接下来,因为我们不知道完整情况,您可以尝试查看片段管理器是否已经拥有您的片段

类似这样的东西(伪代码…)

通过这种方式,您可以添加带有标记的片段(只需一个字符串来标识它们),然后检查片段管理器是否已经拥有它并使用它,而不是总是创建一个新实例

最后但并非最不重要的一点是,这可能受到许多其他(外部)因素的影响:

  • 您正在使用的Fragment/Appcompat/AndroidX/等的版本(正如您可能知道的,Fragment Manager不是Android中最好的类…所以很多修复和更改总是在发生)

  • Android版本:一些Android API比其他API有更好的“片段运气”(特别是在我们有单独的工件来更改“片段”版本之前)

  • 我不认为Koin有什么可以补充的,但请确保您至少使用了最新的稳定版本

  • 也许你能做的最好的事情就是依赖一个ViewModel,而不是所有这些
    if(!detached){…}
    的东西。你真的在与框架作斗争,在FragmentManager中挣扎,这是谷歌有时都不敢做的事情


  • 为什么一个片段会访问另一个片段?是的,一个片段调用另一个片段=1st警告。那么,您如何/何时调用
    addFragment()
    ?您的片段setRetainInstance=true?如何分离它们?(为什么)?@MartinMarconcini我没有将其与代码分离,我唯一做的事情是旋转手机,我没有更改retainInstance默认值OK,以及如何/何时/何地在onCreateView方法中调用addFragmentIn:
    onCreateView(…)如果(savedInstanceState==null)addFragment()
    我添加了共享视图模型,不再从另一个片段调用片段公共方法,这很有帮助。你救了我,谢谢你的努力。祝你愉快:)
            if (savedInstanceState == null) {
                val newFragment = supportFragmentManager.findFragmentByTag(SearchResultFragment::class.java.simpleName) ?: SearchResultFragment.newInstance()
                
                supportFragmentManager.commit {
                    replace(
                        R.id.simple_fragment_container,
                        newFragment,
                        SearchResultFragment::class.java.simpleName
                    )
                }
            }