当前位置: 首页 > 知识库问答 >
问题:

当我在LiveData observer中使用navController时,Android导航组件图停止正常工作

龚振濂
2023-03-14

我在演示应用程序中使用android导航组件。我有一个非常简单的案例。一个活动,两个片段,A和B。我在谷歌的示例应用程序中设置了导航控件。当我试图使用简单的onClickListener打开片段B时,如下所示:

val button.setOnClickListener {
       val action = AFragmentDirections.openFragmentB()
       findNavController().navigate(action)
    }

一切正常。B片段打开,点击后退按钮弹出。但当我试图从LiveData observer中使用它时,就像这样:

viewModel.openFragmentB.observe(viewLifecycleOwner, Observer {
        val action = AFragmentDirections.openFragmentB()
        findNavController().navigate(action)
    })

片段B打开,但通过点击后退按钮应用程序崩溃,错误导航目标com.myapp: id/open_fragmetn_b对此NavController未知。

为什么会发生这种情况,以及如何将导航组件用于LiveData?

共有2个答案

蒋俊
2023-03-14

谢谢@Alex的回答,我创建了与你提到的相同的CALS,并且只添加了初始可选构造函数,如下所示:

import android.util.Log
import androidx.annotation.MainThread
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import java.util.concurrent.atomic.AtomicBoolean

class SingleLiveEvent<T>(initialVal: T? = null) : MutableLiveData<T?>() {

    init {
        if(initialVal != null)
            super.setValue(initialVal)
    }

    private val mPending = AtomicBoolean(false)
    @MainThread
    override fun observe(owner: LifecycleOwner, observer: Observer<in T?>) {
        if (hasActiveObservers()) {
            Log.w(TAG, "Multiple observers registered but only one will be notified of changes.")
        }

        // Observe the internal MutableLiveData
        super.observe(owner, { t ->
            if (mPending.compareAndSet(true, false)) {
                observer.onChanged(t)
            }
        })
    }

    @MainThread
    override fun setValue(t: T?) {
        mPending.set(true)
        super.setValue(t)
    }

    /**
     * Used for cases where T is Void, to make calls cleaner.
     */
    @MainThread
    fun call() {
        value = null
    }

    companion object {
        private const val TAG = "SingleLiveEvent"
    }
}
方飞白
2023-03-14

发生此崩溃是因为当您单击后退按钮时,您的视图模型openFragmentB观察者再次收到通知,并且它正在尝试使用操作openFragmentB导航到片段B,但此时NavController当前目标仍然是片段B,并且片段B没有操作openFragmentB。

对此有多种解决方案,简单的一种是在观察者内部添加检查值是否为null,最后将openFragmentB值设置为null:

if(it!=null) {
    val action = AFragmentDirections.openFragmentB()
    findNavController().navigate(action)
    viewModel.openFragmentB.value=null
}

但要获得更好的方法,您可以阅读有关SingleLIveEvent的内容:https://medium.com/androiddevelopers/livedata-with-snackbar-navigation-and-other-events-the-singleliveevent-case-ac2622673150

 类似资料:
  • 我目前正在我的项目中使用Android导航架构。它有一个功能,可以使用快捷方式启动任何片段。假设我的导航图如下所示:A-

  • 现在,我需要合并一个使用log4j2的库。当我这样做时,我丢失了主应用程序的控制台日志记录(尽管日志消息仍然被写入以编程方式创建的文件追加器)。 我认为,由于文件追加器在原始应用程序中工作,我可以通过在主应用程序中以编程方式创建一个控制台追加器来解决我的问题。然而,我不知道这是对的还是胡说八道。 那么,我的问题是:关于使和log4j2互操作,我需要了解什么一般性的知识吗?如果原始应用程序编码不正确

  • 我正在一个新的Android应用程序上使用导航组件,但我不知道怎么做 首先,我有我的主活动,我有main_navigation_graph 主要活动 NavHostFragment main_navigation_graph里面有3个碎片 这里一切都很好。问题是当我到达最后一个片段时,因为在这个片段上,我想根据BottomNavigationView输入(暂时)显示一些子片段(在新的NavHost

  • 我目前正在我的项目中使用Android导航架构。它有一个功能,可以通过快捷方式启动任何片段。目前我正在使用NavController在单击快捷方式时导航到所需的目的地。但是当我多次单击快捷方式时,每次都会创建一个新的片段实例。所以,我的问题是,有没有办法在使用NavController导航到一个片段时只接受一个片段实例?我谷歌了很多次,但一无所获。提前感谢。

  • 问题内容: 我有一个导航图,该导航图将此片段用作主活动XML中的主页。 我有一个带有菜单的Drawer布局,单击导航抽屉按钮时,我无法设法使导航正常工作(它可以从主要片段工作,但是当我单击Drawer按钮时,不能工作),如果我使用的是旧方法使用:对导航抽屉编程,我的navcontroller丢失了!!我得到类似的错误 navcontroller无法识别目标片段,因为即使不是这种情况,控制器也会看到

  • 我有一个导航图,它在主活动XML中使用这个片段作为主页。 我有一个带菜单的抽屉布局,当我点击抽屉菜单按钮时,我无法使导航工作(它从主片段工作,但当我点击抽屉按钮时就不工作),如果我使用旧的方式来编程抽屉菜单: