【问题标题】:How can I find NavController if I use view binding?如果我使用视图绑定,如何找到 NavController?
【发布时间】:2021-05-28 23:47:33
【问题描述】:

通常,我在代码 A 中使用 val navController: NavController = findNavController(R.id.nav_host_fragment) 来查找 NavController,它基于 R.id.nav_host_fragment

现在我在应用程序中使用视图绑定,就像代码 B 一样,如果我使用视图绑定,我如何导航控制器?

顺便说一句,在我看来 R.id.nav_host_fragment 在视图绑定中不可用,对吧?

代码 A

class TasksActivity : AppCompatActivity() { 

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.tasks_act)

        val navController: NavController = findNavController(R.id.nav_host_fragment)
     }
 
}

代码 B

class TasksActivity : AppCompatActivity() {
    
    private lateinit var binding: TasksActBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = TasksActBinding.inflate(layoutInflater)
        val view = binding.root
        setContentView(view)       
      
        //val navController: NavController = findNavController(R.id.nav_host_fragment)       
    }

}

tasks_act.xml

<androidx.drawerlayout.widget.DrawerLayout
    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/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".tasks.TasksActivity"
    tools:openDrawer="start">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <com.google.android.material.appbar.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <androidx.appcompat.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:minHeight="?attr/actionBarSize"
                android:theme="@style/Toolbar"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
        </com.google.android.material.appbar.AppBarLayout>

        <fragment
            android:id="@+id/nav_host_fragment"
            android:name="androidx.navigation.fragment.NavHostFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"

            app:defaultNavHost="true"
            app:navGraph="@navigation/nav_graph" />

    </LinearLayout>

    ..

</androidx.drawerlayout.widget.DrawerLayout>

【问题讨论】:

    标签: android android-jetpack


    【解决方案1】:

    代码 B 应该仍然可以正常工作。

    我查看了 findNavController() 。这是一个简化代码的扩展函数,扩展函数的代码是

    fun Activity.findNavController(@IdRes viewId: Int): NavController =
        Navigation.findNavController(this, viewId)
    

    现在在Navigation 中查看findNavController() 的代码,我们在下面看到

     @NonNull
        public static NavController findNavController(@NonNull Activity activity, @IdRes int viewId) {
            View view = ActivityCompat.requireViewById(activity, viewId);
            NavController navController = findViewNavController(view);
            if (navController == null) {
                throw new IllegalStateException("Activity " + activity
                        + " does not have a NavController set on " + viewId);
            }
            return navController;
        }
    

    我们传入参数的viewId用在第一行

    View view = ActivityCompat.requireViewById(activity, viewId);
    

    现在我们看到ActivityCompat 内部的requireViewById()

      @NonNull
        public static <T extends View> T requireViewById(@NonNull Activity activity, @IdRes int id) {
            if (Build.VERSION.SDK_INT >= 28) {
                return activity.requireViewById(id);
            }
    
            T view = activity.findViewById(id);
            if (view == null) {
                throw new IllegalArgumentException("ID does not reference a View inside this Activity");
            }
            return view;
        }
    

    对于 api 28 以及被调用的方法是

    @NonNull
        public final <T extends View> T requireViewById(@IdRes int id) {
            T view = findViewById(id);
            if (view == null) {
                throw new IllegalArgumentException("ID does not reference a View inside this Activity");
            }
            return view;
        }
    

    只要视图(其中存在nav_host_fragment)附加到活动,您为查找导航控制器编写的代码应该可以完全正常工作。

    class TasksActivity : AppCompatActivity() {
        
        private lateinit var binding: TasksActBinding
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
    
            binding = TasksActBinding.inflate(layoutInflater)
            val view = binding.root
            setContentView(view)       //you are attaching view to activity here , make sure you always call this before the next line , else you will get IllegalStateException 
          
            val navController: NavController = findNavController(R.id.nav_host_fragment)       
        }
    
    }
    

    我没有亲自测试过代码,但我认为它应该可以正常工作。

    【讨论】:

      【解决方案2】:

      我们正在使用 ViewBinding 来获取视图本身的引用。如果您在 TextView 中使用视图绑定,您将获得该视图的引用。

      在 NavCotroller 的情况下,如果您使用 Viewbinding,您将获得对片段的引用,而 findNavController 需要整数类型的 ViewId。

      findNavController(@IdRes viewId: int)
      

      【讨论】:

      • 谢谢!但是findNavController(@IdRes viewId: int) 需要参数viewId,它在视图绑定中可用吗?
      • 我不确定,但你可以查看这个答案:stackoverflow.com/questions/60733289/…
      • viewId 将可用,绑定主要是语法糖,因此不需要为每个视图使用 findViewById,例如你可以使用binding.toolbar 而不是val toolbar= findViewById&lt;Toolbar&gt;(R.id.toolbar)。你仍然可以,但如果你有绑定,你为什么要这样做?
      【解决方案3】:

      正确的工作方式如下:

      FragmentContainerView 必须从 supportFragmentManager 访问:

      val navHostFragment = supportFragmentManager.findFragmentById(R.id.fragment) as NavHostFragment
      
      val navController = navHostFragment.navController
      

      【讨论】:

        猜你喜欢
        • 2021-02-23
        • 1970-01-01
        • 2017-04-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多