设备旋转后 NavController 没有当前导航节点
NavController no current navigation node after device rotation
我正在制作支持不同设备方向的应用程序。导航由 Android Jetpack 的导航执行。横向的应用程序主屏幕如下所示。它是list wrapper fragment(它是NavHostFragment
,它被添加到activity的layout in fragment
标签),wrapper包括list fragment(fragment
)和details fragment( FrameLayout
)。纵向方向相似(其中包含包装器和列表,详细信息可通过抛出导航访问)。
我的问题是在更改设备方向后出现异常
java.lang.IllegalStateException: no current navigation node
我的带有模拟数据的布局的第一个版本工作正常,在我将 ROOM 添加到我的应用程序、新订单和更新订单片段后出现错误。很遗憾,我无法更准确地定位错误来源。
列表包装器代码
class OrderListWrapperFragment : RxFragment() {
private val disposable = CompositeDisposable()
var selectedOrderId: Long = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val bundle = savedInstanceState ?: arguments
bundle?.let {
selectedOrderId = it.getLong(EXTRA_ORDER_ID)
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? = inflater.inflate(R.layout.orders__list_wrapper, container, false)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initializeToolbar(toolbar, getString(R.string.orders_title), false)
newOrderButton
.clicks()
.subscribe {
findNavController()
.navigate(R.id.action_orderListWrapperFragment_to_orderNewFragment)
}
.addTo(disposable)
childFragmentManager.registerFragmentLifecycleCallbacks(callback, false)
}
override fun onDestroyView() {
super.onDestroyView()
childFragmentManager.unregisterFragmentLifecycleCallbacks(callback)
disposable.clear()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putLong(EXTRA_ORDER_ID, selectedOrderId)
}
private val callback = object : FragmentManager.FragmentLifecycleCallbacks() {
private val disposable = CompositeDisposable()
override fun onFragmentResumed(fm: FragmentManager, fragment: Fragment) {
super.onFragmentResumed(fm, fragment)
if (fragment is OrderListFragment) {
fragment
.selectedItemIdChanges
.subscribeBy(onNext = {
selectedOrderId = it
if (orderDetailsContainer != null) {
childFragmentManager.commit {
replace(
R.id.orderDetailsContainer,
OrderDetailsFragment.newInstance(it)
)
}
} else {
findNavController()
.navigate(
R.id.action_orderListWrapperFragment_to_orderDetailsFragment,
bundleOf(EXTRA_ORDER_ID to it)
)
selectedOrderId = 0
}
},
onError = {
Log.d("detailView", it.toString())
})
.addTo(disposable)
val orderId = selectedOrderId
if (orderId != 0L) {
if (orderDetailsContainer != null) {
childFragmentManager.commit {
replace(
R.id.orderDetailsContainer,
OrderDetailsFragment.newInstance(orderId)
)
}
} else {
findNavController()
.navigate(//exception throws here
R.id.action_orderListWrapperFragment_to_orderDetailsFragment,
bundleOf(EXTRA_ORDER_ID to orderId)
)
selectedOrderId = 0
}
}
}
}
override fun onFragmentPaused(fm: FragmentManager, fragment: Fragment) {
super.onFragmentPaused(fm, fragment)
if (fragment is OrderListFragment) {
disposable.clear()
}
}
}
companion object {
private const val EXTRA_ORDER_ID = "EXTRA_ORDER_ID"
}
}
我的导航图
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/navigation_graph"
app:startDestination="@id/orderListWrapperFragment">
<fragment
android:id="@+id/orderListWrapperFragment"
android:name="com.mtgshipping.app.orders.orderList.OrderListWrapperFragment"
android:label="OrderListWrapperFragment"
tools:layout="@layout/orders__list_wrapper">
<action
android:id="@+id/action_orderListWrapperFragment_to_orderDetailsFragment"
app:destination="@id/orderDetailsFragment"/>
<action
android:id="@+id/action_orderListWrapperFragment_to_orderNewFragment"
app:destination="@id/orderNewFragment"/>
<action
android:id="@+id/action_orderListWrapperFragment_to_orderUpdateFragment"
app:destination="@id/orderUpdateFragment"/>
</fragment>
<fragment
android:id="@+id/orderDetailsFragment"
android:name="com.mtgshipping.app.orders.orderDetails.OrderDetailsFragment"
android:label="OrderDetailsFragment"
tools:layout="@layout/orders__order_details">
<action
android:id="@+id/action_orderDetailsFragment_to_orderUpdateFragment"
app:destination="@id/orderUpdateFragment"/>
</fragment>
<fragment
android:id="@+id/orderNewFragment"
android:name="com.mtgshipping.app.orders.orderNew.OrderNewFragment"
android:label="OrderNewFragment"
tools:layout="@layout/orders__order_new">
<action
android:id="@+id/action_orderNewFragment_to_orderListWrapperFragment"
app:destination="@id/orderListWrapperFragment"/>
</fragment>
<fragment
android:id="@+id/orderUpdateFragment"
android:name="com.mtgshipping.app.orders.orderUpdate.OrderUpdateFragment"
android:label="OrderUpdateFragment"
tools:layout="@layout/orders__order_update">
<action
android:id="@+id/action_orderUpdateFragment_to_orderListWrapperFragment"
app:destination="@id/orderListWrapperFragment"/>
</fragment>
</navigation>
我在NavController
中做了一些调试,在第746行NavDestination currentNode = mBackStack.isEmpty() ? mGraph : mBackStack.getLast().getDestination();
显示设备轮换后mGraph
是null
,其他私有字段也是null
.也许某些东西阻止 NavController
正确初始化。如果需要,我可以提供布局和其他代码。
感谢 Slav 的评论,他是对的。我在应用模块 build.gradle
中将导航模块更新为 2.2.0 navigation_version = '2.2.0'
implementation "androidx.navigation:navigation-fragment-ktx:$navigation_version"
implementation "androidx.navigation:navigation-ui-ktx:$navigation_version"
完成后这个问题不再出现,看起来是导航中的错误。
你也可以这样修复。
在您的主机 activity 清单中添加此属性:
<activity android:name=".MainActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
但最好的方法是更改您的导航依赖项:
implementation "android.arch.navigation:navigation-fragment-ktx:$navigation_version"
implementation "android.arch.navigation:navigation-ui-ktx:$navigation_version"
至
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
我的问题是生命周期依赖的版本
"androidx.lifecycle:lifecycle-extensions:$lifecycle_version
版本'2.2.0'导致问题,我返回使用'2.1.0'
lifecycle_version = '2.1.0'
None 这些解决方案解决了我的问题。
我通过将嵌套图包含到主图中来修复它。
我有一个 nav_main
,其中包括一个 nav_sub_1
。
nav_sub_1
还包括另一个子图,nav_sub_2
当我尝试通过设置 nav_sub_2
来启动我的 activity 时,IllegalStateException
发生了
java.lang.IllegalStateException: no current navigation node
但设置 nav_main
或 nav_sub_1
不会发生这种情况。
我的主图 nav_main
看起来像这样:
<navigation
<fragment...>
<include app:graph="@navigation/nav_sub_1
<navigation/>
和nav_sub_1
:
<navigation
<fragment...>
<include app:graph="@navigation/nav_sub_2
<navigation/>
我将 nav_sub_2 包含在 nav_main 中,问题已解决!
<navigation
<fragment...>
<include app:graph="@navigation/nav_sub_1
<include app:graph="@navigation/nav_sub_2
<navigation/>
对我来说片段错了parent。改变这个
class MyFragment: DynamicNavHostFragment() ...
至此
class MyFragment: Fragment() ...
已解决该问题
我正在制作支持不同设备方向的应用程序。导航由 Android Jetpack 的导航执行。横向的应用程序主屏幕如下所示。它是list wrapper fragment(它是NavHostFragment
,它被添加到activity的layout in fragment
标签),wrapper包括list fragment(fragment
)和details fragment( FrameLayout
)。纵向方向相似(其中包含包装器和列表,详细信息可通过抛出导航访问)。
我的问题是在更改设备方向后出现异常
java.lang.IllegalStateException: no current navigation node
我的带有模拟数据的布局的第一个版本工作正常,在我将 ROOM 添加到我的应用程序、新订单和更新订单片段后出现错误。很遗憾,我无法更准确地定位错误来源。
列表包装器代码
class OrderListWrapperFragment : RxFragment() {
private val disposable = CompositeDisposable()
var selectedOrderId: Long = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val bundle = savedInstanceState ?: arguments
bundle?.let {
selectedOrderId = it.getLong(EXTRA_ORDER_ID)
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? = inflater.inflate(R.layout.orders__list_wrapper, container, false)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initializeToolbar(toolbar, getString(R.string.orders_title), false)
newOrderButton
.clicks()
.subscribe {
findNavController()
.navigate(R.id.action_orderListWrapperFragment_to_orderNewFragment)
}
.addTo(disposable)
childFragmentManager.registerFragmentLifecycleCallbacks(callback, false)
}
override fun onDestroyView() {
super.onDestroyView()
childFragmentManager.unregisterFragmentLifecycleCallbacks(callback)
disposable.clear()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putLong(EXTRA_ORDER_ID, selectedOrderId)
}
private val callback = object : FragmentManager.FragmentLifecycleCallbacks() {
private val disposable = CompositeDisposable()
override fun onFragmentResumed(fm: FragmentManager, fragment: Fragment) {
super.onFragmentResumed(fm, fragment)
if (fragment is OrderListFragment) {
fragment
.selectedItemIdChanges
.subscribeBy(onNext = {
selectedOrderId = it
if (orderDetailsContainer != null) {
childFragmentManager.commit {
replace(
R.id.orderDetailsContainer,
OrderDetailsFragment.newInstance(it)
)
}
} else {
findNavController()
.navigate(
R.id.action_orderListWrapperFragment_to_orderDetailsFragment,
bundleOf(EXTRA_ORDER_ID to it)
)
selectedOrderId = 0
}
},
onError = {
Log.d("detailView", it.toString())
})
.addTo(disposable)
val orderId = selectedOrderId
if (orderId != 0L) {
if (orderDetailsContainer != null) {
childFragmentManager.commit {
replace(
R.id.orderDetailsContainer,
OrderDetailsFragment.newInstance(orderId)
)
}
} else {
findNavController()
.navigate(//exception throws here
R.id.action_orderListWrapperFragment_to_orderDetailsFragment,
bundleOf(EXTRA_ORDER_ID to orderId)
)
selectedOrderId = 0
}
}
}
}
override fun onFragmentPaused(fm: FragmentManager, fragment: Fragment) {
super.onFragmentPaused(fm, fragment)
if (fragment is OrderListFragment) {
disposable.clear()
}
}
}
companion object {
private const val EXTRA_ORDER_ID = "EXTRA_ORDER_ID"
}
}
我的导航图
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/navigation_graph"
app:startDestination="@id/orderListWrapperFragment">
<fragment
android:id="@+id/orderListWrapperFragment"
android:name="com.mtgshipping.app.orders.orderList.OrderListWrapperFragment"
android:label="OrderListWrapperFragment"
tools:layout="@layout/orders__list_wrapper">
<action
android:id="@+id/action_orderListWrapperFragment_to_orderDetailsFragment"
app:destination="@id/orderDetailsFragment"/>
<action
android:id="@+id/action_orderListWrapperFragment_to_orderNewFragment"
app:destination="@id/orderNewFragment"/>
<action
android:id="@+id/action_orderListWrapperFragment_to_orderUpdateFragment"
app:destination="@id/orderUpdateFragment"/>
</fragment>
<fragment
android:id="@+id/orderDetailsFragment"
android:name="com.mtgshipping.app.orders.orderDetails.OrderDetailsFragment"
android:label="OrderDetailsFragment"
tools:layout="@layout/orders__order_details">
<action
android:id="@+id/action_orderDetailsFragment_to_orderUpdateFragment"
app:destination="@id/orderUpdateFragment"/>
</fragment>
<fragment
android:id="@+id/orderNewFragment"
android:name="com.mtgshipping.app.orders.orderNew.OrderNewFragment"
android:label="OrderNewFragment"
tools:layout="@layout/orders__order_new">
<action
android:id="@+id/action_orderNewFragment_to_orderListWrapperFragment"
app:destination="@id/orderListWrapperFragment"/>
</fragment>
<fragment
android:id="@+id/orderUpdateFragment"
android:name="com.mtgshipping.app.orders.orderUpdate.OrderUpdateFragment"
android:label="OrderUpdateFragment"
tools:layout="@layout/orders__order_update">
<action
android:id="@+id/action_orderUpdateFragment_to_orderListWrapperFragment"
app:destination="@id/orderListWrapperFragment"/>
</fragment>
</navigation>
我在NavController
中做了一些调试,在第746行NavDestination currentNode = mBackStack.isEmpty() ? mGraph : mBackStack.getLast().getDestination();
显示设备轮换后mGraph
是null
,其他私有字段也是null
.也许某些东西阻止 NavController
正确初始化。如果需要,我可以提供布局和其他代码。
感谢 Slav 的评论,他是对的。我在应用模块 build.gradle
navigation_version = '2.2.0'
implementation "androidx.navigation:navigation-fragment-ktx:$navigation_version"
implementation "androidx.navigation:navigation-ui-ktx:$navigation_version"
完成后这个问题不再出现,看起来是导航中的错误。
你也可以这样修复。 在您的主机 activity 清单中添加此属性:
<activity android:name=".MainActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
但最好的方法是更改您的导航依赖项:
implementation "android.arch.navigation:navigation-fragment-ktx:$navigation_version"
implementation "android.arch.navigation:navigation-ui-ktx:$navigation_version"
至
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
我的问题是生命周期依赖的版本
"androidx.lifecycle:lifecycle-extensions:$lifecycle_version
版本'2.2.0'导致问题,我返回使用'2.1.0'
lifecycle_version = '2.1.0'
None 这些解决方案解决了我的问题。
我通过将嵌套图包含到主图中来修复它。
我有一个 nav_main
,其中包括一个 nav_sub_1
。
nav_sub_1
还包括另一个子图,nav_sub_2
当我尝试通过设置 nav_sub_2
来启动我的 activity 时,IllegalStateException
发生了
java.lang.IllegalStateException: no current navigation node
但设置 nav_main
或 nav_sub_1
不会发生这种情况。
我的主图 nav_main
看起来像这样:
<navigation
<fragment...>
<include app:graph="@navigation/nav_sub_1
<navigation/>
和nav_sub_1
:
<navigation
<fragment...>
<include app:graph="@navigation/nav_sub_2
<navigation/>
我将 nav_sub_2 包含在 nav_main 中,问题已解决!
<navigation
<fragment...>
<include app:graph="@navigation/nav_sub_1
<include app:graph="@navigation/nav_sub_2
<navigation/>
对我来说片段错了parent。改变这个
class MyFragment: DynamicNavHostFragment() ...
至此
class MyFragment: Fragment() ...
已解决该问题