0

我使用 Android Studio 中的底部导航活动模板创建了一个应用程序。在主要活动的 onCreate() 方法中,我向 NavController 添加了一个 OnDestinationChangedListener。我想在选定的 Fragment 更改后调用一些方法。如何从侦听器中的 onDestinationChanged() 获取选定的片段?onCreate() 代码如下:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        BottomNavigationView navView = findViewById(R.id.nav_view);
        // Passing each menu ID as a set of Ids because each
        // menu should be considered as top level destinations.
        AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
                R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications)
                .build();
        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
        NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
        NavigationUI.setupWithNavController(navView, navController);

        navController.addOnDestinationChangedListener(
                new NavController.OnDestinationChangedListener() {
                    @Override
                    public void onDestinationChanged(@NonNull NavController controller, @NonNull NavDestination destination, @Nullable Bundle arguments) {
                        switch (destination.getId()) {
                            case R.id.navigation_home: {
                                Log.i(TAG, "navigation_home");
                                // Here is where I want to get the HomeFragment instance.
                                break;
                            }
                        }
                    }
                }
        );
    }

编辑:请注意我不是自己创建片段,请参阅调用之前的三行navController.addOnDestinationChangedListener()

编辑:这是activity_main.xml中的 Xml :

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingTop="?attr/actionBarSize">

    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/nav_view"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="0dp"
        android:layout_marginEnd="0dp"
        android:background="?android:attr/windowBackground"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:menu="@menu/bottom_nav_menu" />

    <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:layout_constraintBottom_toTopOf="@id/nav_view"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:navGraph="@navigation/mobile_navigation" />

</androidx.constraintlayout.widget.ConstraintLayout>

对于bottom_nav_menu.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:id="@+id/navigation_home"
        android:icon="@drawable/ic_home_black_24dp"
        android:title="@string/title_home" />

    <item
        android:id="@+id/navigation_dashboard"
        android:icon="@drawable/ic_dashboard_black_24dp"
        android:title="@string/title_dashboard" />

    <item
        android:id="@+id/navigation_notifications"
        android:icon="@drawable/ic_notifications_black_24dp"
        android:title="@string/title_notifications" />

</menu>

对于fragment_home.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ui.home.HomeFragment">

    <TextView
        android:id="@+id/text_home"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:textAlignment="center"
        android:textSize="20sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

fragment_dashboard.xmlfragment_notifications.xml与fragment_home.xml非常相似。

这是HomeFragment的代码

public class HomeFragment extends Fragment {
    private final static String TAG = BleService.class.getSimpleName();

    private HomeViewModel homeViewModel;

    public View onCreateView(@NonNull LayoutInflater inflater,
                             ViewGroup container, Bundle savedInstanceState) {
        homeViewModel = new ViewModelProvider(this).get(HomeViewModel.class);
        View root = inflater.inflate(R.layout.fragment_home, container, false);

        final TextView textView = root.findViewById(R.id.text_home);
        homeViewModel.getText().observe(getViewLifecycleOwner(), new Observer<String>() {
            @Override
            public void onChanged(@Nullable String s) {
                textView.setText(s);
            }
        });

        return root;
    }
}

对于HomeViewModel

public class HomeViewModel extends ViewModel {

    private MutableLiveData<String> mText;

    public HomeViewModel() {
        mText = new MutableLiveData<>();
        mText.setValue("This is home fragment");
    }

    public LiveData<String> getText() {
        return mText;
    }
}

除了我一直在做的关于创建一个 Service 及其使用MainActivity的测试之外,项目的其余部分几乎是我创建项目时由 AndroidStudio 生成的代码。

4

2 回答 2

0

实际上,您需要像这样在 navView 上传递 setNavigationItemSelectedListener navView.setNavigationItemSelectedListener(this); 然后将此代码添加到您的 onNavigationItemSelected案例 R.id.navigation_home: Navigation.findNavController(this,R.id.nav_host_fragment).navigate(R.id.profile); 注意:将 R.id.profile 替换为您的导航图。代码只是您想要实现的示例。不要忘记在主 Activity 中实现 NavigationView.onNavigationItemSelectedListener

于 2021-02-11T06:17:22.767 回答
0

显然,在对onDestinationChanged(). 在创建片段之前调用此侦听器的方法。另一个类似问题中的几个答案建议使用类似的东西(null为简单起见,删除了注释检查):

Fragment navHostFragment = getSupportFragmentManager().getPrimaryNavigationFragment();
Fragment currentFragment = navHostFragment.getChildFragmentManager().getFragments().get(0);

但各州的文件NavController.OnDestinationChangedListener

导航完成后调用此方法,但关联的转场可能仍在播放。

所以,在玩上面的代码时,第一次onDestinationChanged()被调用,返回的片段列表navHostFragment.getChildFragmentManager().getFragments()是空的,这与之前的文档摘录一致。但是第二次调用它navController的列表确实包含 1 个元素,在我的例子中,是在更改之前选择的那个。

应该有更多的方法来实现这一点,但我发现将数据传递给片段的方法是这样的:

  1. 创建一个助手Binder作为参数传递给Fragment

     public interface IMyAppServices {
         String getSomeText();
     }
    
     public class MyAppServicesBinder extends Binder {
         public IMyAppServices getService() {
             return new IMyAppServices() {
                 @Override
                 public String getSomeText() {
                     return "This is some text";
                 }
             };
         }
     }
    
     private final MyAppServicesBinder _myAppServicesBinder = new MyAppServicesBinder();
    
  2. NavController's 的初始化中添加以下代码,请注意这仅用于测试目的,请参见此处文档中的示例:

     NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
     Bundle args = new Bundle();
     args.putString("My string", "Is this");
     args.putBinder("MyAppServices", _myAppServicesBinder);
     navController.setGraph(R.navigation.mobile_navigation, args);
    
  3. 现在Fragment可以通过这样的调用来读取这些参数getArguments()

     @Override
     public void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         Bundle arguments = getArguments();
         MainActivity.MyAppServicesBinder binder = (MainActivity.MyAppServicesBinder)arguments.getBinder("MyAppServices");
         String someText = binder.getService().getSomeText();
         Log.i(TAG, "onCreate() called with SomeTest = " + someText); 
     }
    

这为我提供了从Fragment. 现在的问题是如何以一种简单的方式做相反的事情,并由所选内容发生变化的事件触发Fragment

于 2021-02-11T16:49:56.620 回答