NavigationView 的 MVVM ViewModel 数据绑定应该是什么样子

How the MVVM ViewModel DataBinding shoud look like for NavigationView

我没有找到任何示例来说明这一点。我刚开始接触 MVVM DataBinding 和 ViewModel。

我想在单击 DrawerLayout 中 NavigationView 中的元素后执行一个操作。如果没有任何设计模式,我会以非常简单的方式做到这一点,但这个 MVVM 是非常困难的模式。

我在考虑 ViewModelMain 中的 MutableLiveData,然后在 ActivityMain 中观察它,但我不知道在这个例子中要观察什么。

这是我的代码:

ActivityMain.java

(...)

@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
    int id = item.getItemId();
    if(id == R.id.nav_account) {
        Toast.makeText(this, "abc", Toast.LENGTH_SHORT).show();
        drawerLayout.close();
    }
    return false;
}

ViewModelMain.java

public class ViewModelMain extends ViewModel {

}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout 
xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/my_drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <RelativeLayout

        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <FrameLayout
            android:id="@+id/content_frame"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_constraintBottom_toTopOf="@+id/bottom_navigation"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <com.google.android.material.bottomnavigation.BottomNavigationView
            android:id="@+id/bottom_navigation"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:background="?attr/colorBottomNavigationViewBg"
            app:itemHorizontalTranslationEnabled="true"
            app:itemTextColor="?attr/colorBottomNavigationViewItem"
            app:layout_constraintBottom_toBottomOf="parent"
            app:menu="@menu/menu_bottom_navigation" />

    </RelativeLayout>

    <com.google.android.material.navigation.NavigationView
        android:id="@+id/navigation_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        app:menu="@menu/menu_navigation_drawer"
        app:itemIconTint="?colorDayNight" />


</androidx.drawerlayout.widget.DrawerLayout>

首先我想指出DataBinding 和ViewBinding 之间的区别。 DataBinding 允许您将布局中的 UI 组件(在 XML 中)绑定到应用程序中的数据源。我对 DataBinding 有点偏见。我不喜欢也不用。

ViewBinding 是一种在您的应用程序代码中绑定视图元素并消除不断编写 findViewById 的需要的方法。它为每个 XML 布局生成一个绑定 class,您可以在 activities/fragments(views) 中使用它。

在您的情况下,您只需使用视图绑定就可以了。 这是 android 文档:https://developer.android.com/topic/libraries/view-binding

接下来取决于您要执行的操作。假设您想显示元素被点击的次数。

您的 ViewModel 将负责处理该逻辑,而您的视图将负责观察和显示更改。 (我会尝试在java中写这个,但我已经很久没有使用Java,你也应该考虑切换到Kotlin)

public class ViewModelMain extends ViewModel {
    private MutableLiveData<Integer> _timesClicked = new MutableLiveData<>();
    
    public void increaseClickCounter() {
        int currentTimesClicked = _timesClicked.getValue();
        _timesClicked.setValue(++currentTimesClicked);
    }

    public LiveData<Integer> getTimesClicked() {
        if (_timesClicked == null) {
            _timesClicked = new MutableLiveData<>();
            _timesClicked.setValue(0);
        }

        return _timesClicked;
    }

}

要阅读 activity 中的视图绑定,您可以访问此处:https://developer.android.com/topic/libraries/view-binding#activities

您现在需要将 viewBinding 和 viewModle 添加到您的 activity。这将成为您 activity 代码的一部分:

private ActivityMainBinding binding; //notice the "Binding" suffix at the end

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
        
    viewModel = new ViewModelProvider(this).get(ViewModelMain.class);

    binding = ActivityMainBinding.inflate(getLayoutInflater());
    View view = binding.getRoot();
    setContentView(view);

    initClickListeners();
    startObservingData();

}

private void initClickListeners() {
    ///replace "yourButton" with an element from your XML. 
    binding.yourButton.setOnClickListener(new View.OnClickListener() {
        viewModel.increaseClickCounter();
    });
}

private void startObservingData() {
    viewModel.getTimesClicked().observe(this, timesClicked -> {
        Toast.makeText(this, timesClicked.intValue(), Toast.LENGTH_SHORT).show();
    });

}