在BaseFragment中使用导航组件

时间:2019-06-25 09:59:56

标签: android android-fragments android-architecture-navigation android-optionsmenu

在我的应用程序中,我有一个OptionsMenu,许多Fragment都使用它。因此,我创建了以下BaseFragment:

abstract class BaseFragment : Fragment() {

private lateinit var navController: NavController

protected fun askForPermissions(permissionRequestCode: Int, vararg permissions: String) {
    requestPermissions(permissions, permissionRequestCode)
}

protected fun checkPermission(permission: String, activity: Activity): Boolean = when {
    Build.VERSION.SDK_INT < Build.VERSION_CODES.M -> true // It is not needed at all as there were no runtime permissions yet
    else -> ContextCompat.checkSelfPermission(activity, permission) == PackageManager.PERMISSION_GRANTED
}

override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
    inflater!!.inflate(R.menu.menu_topbar, menu)

    @SuppressLint("RestrictedApi")
    if (menu is MenuBuilder) {
        menu.setOptionalIconsVisible(true)
    }

    super.onCreateOptionsMenu(menu, inflater)
}

override fun onOptionsItemSelected(item: MenuItem): Boolean {
    navController = Navigation.findNavController(view!!)

    return when (item.itemId) {
        R.id.menu_topbar_profile -> {
            navController.navigate(actionBaseToProfile())
            true
        }
        R.id.menu_topbar_favorites -> {
            navController.navigate(actionBaseToFavorites())
            true
        }
        R.id.menu_topbar_help -> {
            navController.navigate(actionBaseToHelp())
            true
        }
        else -> false
    }
}

}

然后在导航文件中添加了BaseFragment和目标Fragments。这是一个片段:

    <fragment
    android:id="@+id/fragment_base"
    android:name="com.test.scanner.base.BaseFragment">

    <action
        android:id="@+id/action_base_to_profile"
        app:destination="@id/fragment_profile" />
</fragment>

<fragment
    android:id="@+id/fragment_profile"
    android:name="com.test.scanner.ui.profile.ProfileFragment"
    tools:layout="@layout/fragment_profile" />

如您所见,我没有为BaseFragment定义布局,因为没有人。如果我想通过单击OptionsMenu的某个元素导航到特定屏幕(例如ProfileFragment),则始终会收到IllegalArgumentException。例外:

java.lang.IllegalArgumentException: navigation destination com.test.scanner.debug:id/action_base_to_profile is unknown to this NavController

我们如何在BaseFragment中使用导航组件。这种情况是否有可能解决?或者有其他解决方案?

3 个答案:

答案 0 :(得分:3)

您正在混合事物。不要将abstract类放入导航图,而只能将扩展此BaseFragment类的类放入您的案例中。我建议您从本教程navigation-architecture-components开始,一旦完成,请尝试阅读有关抽象类的更多信息,然后从本文简化解决方案。完成后,尝试添加菜单,但不要将其放入baseFragment中,而是将不同的菜单放入每个片段中,而对下一个片段仅执行一个操作即可。这样会更容易。将头缠好后,添加按钮之类的新内容。

答案 1 :(得分:1)

如果在项目中使用SaveArgs,请从“ BaseFragment”导航到其他(不是Abstract)片段,请执行以下步骤:

1)在您的navigation.xml中为“ 导航”标签添加“ android:id ”:

<action
    android:id="@+id/itemContent"
    app:destination="@id/destination_item_content" />

2)在“导航”标签内添加不带“片段”的“ 动作”:

val direction = MobileNavigationDirections.itemContent()
findNavController().navigate(direction)

3)重建项目

4)使用刚刚生成的类“ MobileNavigation”。该名称来自您的“导航”标签的ID。

$(this).attr('data-action', 'add-to-cart');

请在此处阅读其他信息:Use Safe Args with a global action

答案 2 :(得分:0)

这似乎是该问题的一个很好的解决方案(并且对我有用):

public class MyFragmentFactory extends FragmentFactory{
    @NonNull
    @Override
    public Fragment instantiate(@NonNull ClassLoader classLoader, @NonNull String className) {
        if (className.equalsIgnoreCase("com.proj.MyBaseFragment")){
            return MyFragmentFactory.getMyFragment();
        }else {
            return super.instantiate(classLoader, className);
        }
    }
}

在您的活动 onCreated 方法中,输入以下内容

    getSupportFragmentManager().setFragmentFactory(new MyFragmentFactory());

基本上,您与 fargement 管理器一起工作,但会接管某些片段的实例化,这些片段只有您知道要根据运行时情况创建。