Jer*_*for 58 android android-architecture-navigation
当我尝试从一个片段导航到另一个片段时,我遇到了新的Android导航架构组件的问题,我得到了这个奇怪的错误:
java.lang.IllegalArgumentException: navigation destination XXX
is unknown to this NavController
Run Code Online (Sandbox Code Playgroud)
每个其他导航工作正常,除了这个特定的导航
我用:
findNavContoller()
Run Code Online (Sandbox Code Playgroud)
Fragment的扩展功能可以访问navControler.
任何帮助将不胜感激.
Cha*_*ere 38
在我的情况下,如果用户非常快速地点击两次相同的视图,则会发生此崩溃.因此,您需要实现某种逻辑以防止多次快速点击......这非常烦人,但似乎是必要的.
你可以在这里阅读更多有关防止这种情况的信息:Android防止双击按钮
小智 30
我为防止崩溃所做的工作如下:
我有一个 BaseFragment,在那里我添加了这个fun以确保它destination被以下的人知道currentDestination:
fun navigate(destination: NavDirections) = with(findNavController()) {
currentDestination?.getAction(destination.actionId)
?.let { navigate(destination) }
}
Run Code Online (Sandbox Code Playgroud)
值得注意的是,我正在使用SafeArgs插件。
the*_*ian 26
currentDestination致电之前进行检查可能会有所帮助。
例如,如果您在导航图fragmentA和上有两个片段目标fragmentB,并且从fragmentA到仅执行一个操作fragmentB。通话navigate(R.id.action_fragmentA_to_fragmentB)将在IllegalArgumentException您已经开启时产生fragmentB。因此,您应该始终currentDestination在浏览前检查。
if (navController.currentDestination?.id == R.id.fragmentA) {
navController.navigate(R.id.action_fragmentA_to_fragmentB)
}
Run Code Online (Sandbox Code Playgroud)
Ale*_*uts 23
您可以在导航控制器的当前目标位置检查请求的操作。
UPDATE 添加了用于安全导航的全局操作的用法。
fun NavController.navigateSafe(
@IdRes resId: Int,
args: Bundle? = null,
navOptions: NavOptions? = null,
navExtras: Navigator.Extras? = null
) {
val action = currentDestination?.getAction(resId) ?: graph.getAction(resId)
if (action != null && currentDestination?.id != action.destinationId) {
navigate(resId, args, navOptions, navExtras)
}
}
Run Code Online (Sandbox Code Playgroud)
Ant*_*hon 21
如果您有一个带有 Fragment B 的 ViewPager 的 Fragment A 并且您尝试从 B 导航到 C,也可能发生这种情况
由于在 ViewPager 中,片段不是 A 的目的地,因此您的图表不会知道您在 B 上。
一个解决方案可以是在 B 中使用 ADirections 导航到 C
Jen*_*anu 10
TL;DRnavigate用try-catch(简单的方法)包裹你的电话,或者确保navigate在短时间内只有一个电话。这个问题可能不会消失。在您的应用中复制更大的代码片段并试用。
你好。基于以上几个有用的回复,我想分享我可以扩展的解决方案。
这是在我的应用程序中导致此崩溃的代码:
@Override
public void onListItemClicked(ListItem item) {
Bundle bundle = new Bundle();
bundle.putParcelable(SomeFragment.LIST_KEY, item);
Navigation.findNavController(recyclerView).navigate(R.id.action_listFragment_to_listItemInfoFragment, bundle);
}
Run Code Online (Sandbox Code Playgroud)
一种轻松重现错误的方法是用多个手指点击项目列表,点击每个项目会在导航到新屏幕中解析(与人们注意到的基本相同 - 在很短的时间内点击两次或多次)。我注意到:
navigate调用总是工作正常;navigate方法的所有其他调用都在IllegalArgumentException.在我看来,这种情况可能会经常出现。由于重复代码是一种不好的做法,并且有一点影响力总是好的,我想到了下一个解决方案:
public class NavigationHandler {
public static void navigate(View view, @IdRes int destination) {
navigate(view, destination, /* args */null);
}
/**
* Performs a navigation to given destination using {@link androidx.navigation.NavController}
* found via {@param view}. Catches {@link IllegalArgumentException} that may occur due to
* multiple invocations of {@link androidx.navigation.NavController#navigate} in short period of time.
* The navigation must work as intended.
*
* @param view the view to search from
* @param destination destination id
* @param args arguments to pass to the destination
*/
public static void navigate(View view, @IdRes int destination, @Nullable Bundle args) {
try {
Navigation.findNavController(view).navigate(destination, args);
} catch (IllegalArgumentException e) {
Log.e(NavigationHandler.class.getSimpleName(), "Multiple navigation attempts handled.");
}
}
Run Code Online (Sandbox Code Playgroud)
}
因此,上面的代码仅在一行中更改:
Navigation.findNavController(recyclerView).navigate(R.id.action_listFragment_to_listItemInfoFragment, bundle);
Run Code Online (Sandbox Code Playgroud)
对此:
NavigationHandler.navigate(recyclerView, R.id.action_listFragment_to_listItemInfoFragment, bundle);
Run Code Online (Sandbox Code Playgroud)
它甚至变得更短了一点。代码在崩溃发生的确切位置进行了测试。没有再体验过,其他导航会用同样的方案,避免进一步出现同样的错误。
欢迎任何想法!
究竟是什么导致了崩溃
请记住,在这里,当我们使用 method 时,我们使用相同的导航图、导航控制器和后台堆栈Navigation.findNavController。
我们总是在这里得到相同的控制器和图形。当UI 尚未更新时,何时navigate(R.id.my_next_destination)调用图形和后台堆栈几乎会立即更改。只是不够快,但没关系。在 back-stack 改变后,导航系统接收第二个navigate(R.id.my_next_destination)调用。由于 back-stack 发生了变化,我们现在相对于堆栈中的顶部片段进行操作。顶部片段是您使用 导航到的片段R.id.my_next_destination,但它不包含接下来任何带有 ID 的其他目的地R.id.my_next_destination。因此,您得到的IllegalArgumentException是片段一无所知的 ID。
这个确切的错误可以在NavController.javamethod 中找到findDestination。
试试看
更新(没有反射和更具可读性)
import androidx.fragment.app.Fragment
import androidx.navigation.NavController
import androidx.navigation.NavDirections
import androidx.navigation.fragment.FragmentNavigator
fun Fragment.safeNavigateFromNavController(directions: NavDirections) {
val navController = findNavController()
val destination = navController.currentDestination as FragmentNavigator.Destination
if (javaClass.name == destination.className) {
navController.navigate(directions)
}
}
Run Code Online (Sandbox Code Playgroud)
旧(带反射)
import androidx.fragment.app.Fragment
import androidx.navigation.NavController
import androidx.navigation.NavDirections
import androidx.navigation.fragment.FragmentNavigator
inline fun <reified T : Fragment> NavController.safeNavigate(directions: NavDirections) {
val destination = this.currentDestination as FragmentNavigator.Destination
if (T::class.java.name == destination.className) {
navigate(directions)
}
}
Run Code Online (Sandbox Code Playgroud)
val direction = FragmentOneDirections.actionFragmentOneToFragmentTwo()
// new usage
safeNavigateFromNavController(direction)
// old usage
// findNavController().safeNavigate<FragmentOne>(action)
Run Code Online (Sandbox Code Playgroud)
我的问题是
我有一个片段 (FragmentOne),它转到另外两个片段(FragmentTwo 和 FragmentThree)。在一些低端设备中,用户按下重定向到 FragmentTwo 的按钮,但在用户按下重定向到 FragmentThree 的按钮后的几毫秒内。结果是:
致命异常:java.lang.IllegalArgumentException 无法从当前目标 Destination(fragmentThree) class=FragmentThree 中找到导航操作/目标 action_fragmentOne_to_fragmentTwo
我的解决方法是:
我检查当前目的地是否属于当前片段。如果为真,我执行导航动作。
就这些!
就我而言,当我将片段中的一个viewpager片段作为viewpager. 的viewpager片段(这是母体片段)在导航XML中加入,但是在不添加动作viewpager父片段。
nav.xml
//reused fragment
<fragment
android:id="@+id/navigation_to"
android:name="com.package.to_Fragment"
android:label="To Frag"
tools:layout="@layout/fragment_to" >
//issue got fixed when i added this action to the viewpager parent also
<action android:id="@+id/action_to_to_viewall"
app:destination="@+id/toViewAll"/>
</fragment>
....
// viewpager parent fragment
<fragment
android:id="@+id/toViewAll"
android:name="com.package.ViewAllFragment"
android:label="to_viewall_fragment"
tools:layout="@layout/fragment_view_all">
Run Code Online (Sandbox Code Playgroud)
通过将操作添加到父 viewpager 片段来修复该问题,如下所示:
nav.xml
//reused fragment
<fragment
android:id="@+id/navigation_to"
android:name="com.package.to_Fragment"
android:label="To Frag"
tools:layout="@layout/fragment_to" >
//issue got fixed when i added this action to the viewpager parent also
<action android:id="@+id/action_to_to_viewall"
app:destination="@+id/toViewAll"/>
</fragment>
....
// viewpager parent fragment
<fragment
android:id="@+id/toViewAll"
android:name="com.package.ViewAllFragment"
android:label="to_viewall_fragment"
tools:layout="@layout/fragment_view_all"/>
<action android:id="@+id/action_to_to_viewall"
app:destination="@+id/toViewAll"/>
</fragment>
Run Code Online (Sandbox Code Playgroud)
今天
def navigationVersion = "2.2.1"
问题仍然存在。我对 Kotlin 的做法是:
// To avoid "java.lang.IllegalArgumentException: navigation destination is unknown to this NavController", se more /sf/ask/3574253371/
fun NavController.navigateSafe(
@IdRes destinationId: Int,
navDirection: NavDirections,
callBeforeNavigate: () -> Unit
) {
if (currentDestination?.id == destinationId) {
callBeforeNavigate()
navigate(navDirection)
}
}
fun NavController.navigateSafe(@IdRes destinationId: Int, navDirection: NavDirections) {
if (currentDestination?.id == destinationId) {
navigate(navDirection)
}
}
Run Code Online (Sandbox Code Playgroud)
就我而言,我使用自定义的后退按钮进行导航。我onBackPressed()代替以下代码进行了调用
findNavController(R.id.navigation_host_fragment).navigateUp()
Run Code Online (Sandbox Code Playgroud)
这导致IllegalArgumentException发生。在将其改为使用该navigateUp()方法后,我再也没有崩溃。
就我而言,我有多个导航图文件,并且我试图从 1 个导航图位置移动到另一个导航图中的目的地。
为此,我们必须将第二个导航图包含在第一个导航图中,如下所示
<include app:graph="@navigation/included_graph" />
Run Code Online (Sandbox Code Playgroud)
并将其添加到您的操作中:
<action
android:id="@+id/action_fragment_to_second_graph"
app:destination="@id/second_graph" />
Run Code Online (Sandbox Code Playgroud)
哪里second_graph:
<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/second_graph"
app:startDestination="@id/includedStart">
Run Code Online (Sandbox Code Playgroud)
在第二张图中。
更多信息请点击此处
您可以在导航之前检查请求导航的 Fragment 是否仍然是当前目的地(取自此 gist )。
\n它基本上在片段上设置一个标签以供以后查找。
\n/**\n * Returns true if the navigation controller is still pointing at \'this\' fragment, or false if it already navigated away.\n */\nfun Fragment.mayNavigate(): Boolean {\n\n val navController = findNavController()\n val destinationIdInNavController = navController.currentDestination?.id\n val destinationIdOfThisFragment = view?.getTag(R.id.tag_navigation_destination_id) ?: destinationIdInNavController\n\n // check that the navigation graph is still in \'this\' fragment, if not then the app already navigated:\n if (destinationIdInNavController == destinationIdOfThisFragment) {\n view?.setTag(R.id.tag_navigation_destination_id, destinationIdOfThisFragment)\n return true\n } else {\n Log.d("FragmentExtensions", "May not navigate: current destination is not the current fragment.")\n return false\n }\n}\nRun Code Online (Sandbox Code Playgroud)\nR.id.tag_navigation_destination_id只是您必须添加到 ids.xml 中的一个 id,以确保它是唯一的。<item name="tag_navigation_destination_id" type="id" />
有关错误和解决方案以及navigateSafe(...)扩展方法的更多信息,请参阅“修复可怕的 \xe2\x80\x9c\xe2\x80\xa6 对于此 NavController\xe2\x80\x9d 来说是未知的”
就我而言,出现错误是因为我在启动屏幕后启用了导航操作Single Top和选项。Clear Task
| 归档时间: |
|
| 查看次数: |
16474 次 |
| 最近记录: |