使用导航从工具栏菜单项单击在片段之间传递数据 - Kotlin

Posted

技术标签:

【中文标题】使用导航从工具栏菜单项单击在片段之间传递数据 - Kotlin【英文标题】:Passing data between fragments from toolbar menu item click using Navigation - Kotlin 【发布时间】:2018-12-09 23:23:33 【问题描述】:

我已经使用导航架构组件设置了我的应用程序。从一个片段导航到下一个片段可以正常工作。但是,我试图在该导航流程中传递数据。

按照Navigation codelab app 的结构,我使用下面的代码在菜单项单击时从一个片段导航到另一个片段:

MainActivity.kt

override fun onOptionsItemSelected(item: MenuItem): Boolean 
    return NavigationUI.onNavDestinationSelected(item,
        Navigation.findNavController(this, R.id.nav_host_fragment))
        || super.onOptionsItemSelected(item)

我尝试通过如下修改代码来传递捆绑包。 android Studio 没有检测到任何错误,但是当我尝试执行该菜单项单击时,我的应用程序崩溃了。请注意,我将R.id.menu_edit 作为findNavController 中的参数传递,因为否则我会收到“没有为参数'viewId'传递值”构建错误-但我认为您通常会在不传递任何内容的情况下调用它。

override fun onOptionsItemSelected(item: MenuItem): Boolean 
    when (item?.itemId) 
        R.id.menu_song_edit -> 
            val songBundle = Bundle()
            songBundle.putString("titleArg", song_title.toString())
            this.findNavController(R.id.menu_song_edit).navigate(R.id.goto_songedit, songBundle) // *** this is line 96 where it crashes per the log ***
            return true
        
        else -> return NavigationUI.onNavDestinationSelected(item,
                Navigation.findNavController(this, R.id.nav_host_fragment))
                || super.onOptionsItemSelected(item)
    

从下面的崩溃记录。没有找到导航控制器?

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.projects.arise.mytestapp, PID: 1162
    java.lang.IllegalStateException: Activity com.projects.arise.mytestapp.MainActivity@58f00cb does not have a NavController set on 2131230836
        at androidx.navigation.Navigation.findNavController(Navigation.java:60)
        at androidx.navigation.ActivityKt.findNavController(Activity.kt:30)
        at com.projects.arise.mytestapp.MainActivity.onOptionsItemSelected(MainActivity.kt:96)
        at android.app.Activity.onMenuItemSelected(Activity.java:3204)
        at android.support.v4.app.FragmentActivity.onMenuItemSelected(FragmentActivity.java:407)
        at android.support.v7.app.AppCompatActivity.onMenuItemSelected(AppCompatActivity.java:195)
        at android.support.v7.view.WindowCallbackWrapper.onMenuItemSelected(WindowCallbackWrapper.java:108)
        at android.support.v7.view.WindowCallbackWrapper.onMenuItemSelected(WindowCallbackWrapper.java:108)
        at android.support.v7.app.ToolbarActionBar$2.onMenuItemClick(ToolbarActionBar.java:63)
        at android.support.v7.widget.Toolbar$1.onMenuItemClick(Toolbar.java:203)
        at android.support.v7.widget.ActionMenuView$MenuBuilderCallback.onMenuItemSelected(ActionMenuView.java:780)
        at android.support.v7.view.menu.MenuBuilder.dispatchMenuItemSelected(MenuBuilder.java:822)
        at android.support.v7.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:171)
        at android.support.v7.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:973)
        at android.support.v7.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:963)
        at android.support.v7.widget.ActionMenuView.invokeItem(ActionMenuView.java:624)
        at android.support.v7.view.menu.ActionMenuItemView.onClick(ActionMenuItemView.java:150)
        at android.view.View.performClick(View.java:5610)
        at android.view.View$PerformClick.run(View.java:22265)
        at android.os.Handler.handleCallback(Handler.java:751)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:154)
        at android.app.ActivityThread.main(ActivityThread.java:6077)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756) Disconnected from the target VM, address: 'localhost:8610', transport: 'socket'

然后我尝试在传递数据的片段中覆盖onOptionsItemSelected,但这似乎没有任何效果。我猜那是因为它已经被上面 MainActivity.kt 中的相同方法拦截了。

我在数据发送片段中的代码如下。资源 ID 'goto_detailsedit' 是指导航 nav_graph.xml 文件中 action 的 ID。

override fun onOptionsItemSelected(item: MenuItem?): Boolean 
    when (item?.itemId) 
        R.id.menu_edit -> 
            val songBundle = Bundle()
            songBundle.putString("nameArg", first_name.text.toString())
            this.findNavController().navigate(R.id.goto_songedit, songBundle)
            return true
        
        else -> return super.onOptionsItemSelected(item)
    

有人可以帮我解决上面 MainActivity.kt 代码中的菜鸟语法错误吗?

2018 年 7 月 2 日更新

再次浏览documentation发现语法应该如下——我需要引用一个视图:

view.findNavController().navigate(R.id.confirmationAction, bundle)

我已经在主Activity的onCreate中设置了工具栏,通过调用:

val toolbar = findViewById<Toolbar>(R.id.toolbar)
    setSupportActionBar(toolbar)

所以我尝试通过将this 替换为toolbar 来引用工具栏:

toolbar.findNavController().navigate(R.id.goto_songedit, songBundle)

Android Studio 代码编辑器现在对它很满意,但我的应用仍然崩溃。日志指出 NavController 尚未设置:

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.projects.arise.mytestapp, PID: 2670
    java.lang.IllegalStateException: View android.support.v7.widget.Toolbard03bbdd V.E...... ........ 0,0-1080,147 #7f0800e0 app:id/toolbar does not have a NavController set
        at androidx.navigation.Navigation.findNavController(Navigation.java:83)
        at androidx.navigation.ViewKt.findNavController(View.kt:28)
        at com.projects.arise.mytestapp.MainActivity.onOptionsItemSelected(MainActivity.kt:96)
        ...

我有什么遗漏吗?或者这可能是导航的错误?

【问题讨论】:

试试 Navigation.findNavController 而不是 this.findNavController 似乎 `Navigation.findNavController' 不会打包,因为我收到错误消息。根据 link 文档,它只需要一个视图或活动和资源 ID。 试试 NavHostFragment.findNavController(nav_host_fragment).navigate(R.id.goto_songedit, songBundle) 无论如何使用bundle不是安全参数,它是常规参数传递,如果你想使用安全参数,你需要声明它们在导航图中。 这行得通!太感谢了!!!您想将其发布为答案吗?然后我会投票并接受它作为正确答案。是的,我今天意识到捆绑不是使用 safeargs 创建的,如果我没记错的话,在接收端使用的是 safeargs。我希望我把后面的部分都正确连接起来了。现在一切都完美无缺!但我明白你的意思,所以我会编辑问题。 ***.com/a/51135410/1268507 【参考方案1】:

你应该使用'NavHostFragment.findNavController()':

    override fun onOptionsItemSelected(item: MenuItem?): Boolean 
    when (item?.itemId)  
        R.id.menu_edit ->  
            val songBundle = Bundle() 
            songBundle.putString("nameArg", first_name.text.toString()) 
            NavHostFragment.findNavController(nav_host_fragment).navigate(R.id.goto_songedit, songBundle) 
            return true 
         
        else -> return super.onOptionsItemSelected(item) 
     
 

【讨论】:

nav_host_fragment 声明在哪里进行这项工作?【参考方案2】:

完美解决方案:

//-------------------/To send Data/--------------------

   val bundle = Bundle()
     bundle.putString("data","Hello World!")
     Navigation.findNavController(view).navigate(R.id.action_firstFragment_to_secondFragment,bundle)


//--------------------/To get data/----------------------------------

 val string = arguments!!.getString("data")
Toast.makeText(context,string,Toast.LENGTH_SHORT).show()

【讨论】:

以上是关于使用导航从工具栏菜单项单击在片段之间传递数据 - Kotlin的主要内容,如果未能解决你的问题,请参考以下文章

热门从另一个片段导航到主页片段

如何将片段目标绑定到底部导航栏中的菜单项?

如何在底部导航片段(或导航抽屉)之间传递数据?

如何在导航抽屉中的两个片段之间传递数据

将数据从活动传递到底部导航栏的片段

使用导航栏按钮项和核心数据在视图控制器之间传递日期