ViewModel数据绑定继承不起作用

时间:2019-04-05 13:53:46

标签: android android-fragments android-databinding android-mvvm

我有一个要迁移到MVVM + Jetpack的MVP应用程序。使用导航体系结构组件(NAC),现在的设置是我有一个NavHostActivity及其布局文件,activity_nav_host.xml包含一个DrawerLayout,一个Toolbar和一个{{1 }}:

NavigationView

使用NAC时,建议使用一个活动和多个片段。在上面的文件中,<?xml version="1.0" encoding="utf-8"?> <layout 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" xmlns:bind="http://schemas.android.com/apk/res-auto"> <data> <variable name="vm" type="com.myapp.base.NavHostViewModel"/> </data> <androidx.drawerlayout.widget.DrawerLayout android:id="@+id/drawer_layout" android:layout_width="match_parent" android:layout_height="match_parent" tools:openDrawer="start" android:fitsSystemWindows="true"> <LinearLayout android:id="@+id/content" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <include android:id="@+id/toolbar" layout="@layout/toolbar_custom" bind:vm="@{vm}"/> <fragment android:id="@+id/fragment_nav_host" android:name="androidx.navigation.fragment.NavHostFragment" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@id/toolbar" app:defaultNavHost="true" app:navGraph="@navigation/graph"/> </LinearLayout> <com.google.android.material.navigation.NavigationView android:id="@+id/nav_drawer" android:layout_width="360dp" android:layout_height="match_parent" android:layout_gravity="start"> <ScrollView android:id="@+id/scroll_view" android:layout_width="match_parent" android:layout_height="match_parent"> <include android:id="@+id/drawer_navigation" layout="@layout/drawer_navigation" /> </ScrollView> </com.google.android.material.navigation.NavigationView> </androidx.drawerlayout.widget.DrawerLayout> </layout> 是这些片段的容器,对于每个屏幕,我打算相应地更改工具栏标题。以下是附带的工具栏(@+id/fragment_nav_host)的内容:

toolbar_custom.xml

以及用于NavHostActivity的ViewModel:

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

    <data>
        <variable name="vm" type="com.myapp.base.NavHostViewModel"/>
    </data>

    <androidx.appcompat.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?android:attr/actionBarSize"
        android:paddingEnd="16dp"
        android:background="@color/colorPrimary"
        app:contentInsetStartWithNavigation="0dp"
        android:elevation="4dp">

        <RelativeLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="16dp"
            android:layout_marginEnd="16dp"
            android:background="@android:color/transparent">

            <TextView
                android:id="@+id/title"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:background="@android:color/transparent"
                android:fontFamily="@font/montserrat_bold"
                android:textColor="@color/colorPrimaryDark"
                android:textSize="20sp"
                android:singleLine="true"
                android:ellipsize="end"
                android:text="@={vm.title}"
                tools:text="Title" />
        </RelativeLayout>
    </androidx.appcompat.widget.Toolbar>
</layout>

最后,这是NavHostActivity本身:

public class NavHostViewModel extends ViewModel {
    public MutableLiveData<String> title = new MutableLiveData<>();

    public NavHostViewModel(String title) {
        this.title.setValue(title);
    }

    static class Factory implements ViewModelProvider.Factory {
        private String title;

        Factory(String title) {
            this.title = title;
        }

        @SuppressWarnings("unchecked")
        @NonNull
        @Override
        public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
            return (T) new NavHostViewModel(title);
        }
    }
}

现在,由于每个片段屏幕都有自己的工具栏标题,并且标题将来自该特定片段的ViewModel,所以我将ViewModel扩展为public class NavHostActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ActivityNavHostBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_nav_host); NavHostViewModel viewModel = ViewModelProviders.of(this, new NavHostViewModel.Factory("MyApp")) .get(NavHostViewModel.class); binding.setVm(viewModel); binding.setLifecycleOwner(this); } } ,然后用{{1 }}调用父构造函数。一个例子:

NavHostViewModel

然后在片段中实例化ViewModel:

super()

所有这些都不产生我所期望的-工具栏中的TextView文本不会更改,并且我只看到实例化public class DashboardViewModel extends NavHostViewModel { public DashboardViewModel(String title) { super(title); } static class Factory implements ViewModelProvider.Factory { private String title; Factory(String title) { this.title = title; } @SuppressWarnings("unchecked") @NonNull @Override public <T extends ViewModel> T create(@NonNull Class<T> modelClass) { return (T) new DashboardViewModel(title); } } } 时最初传递的值。没有错误被抛出。

我看过并尝试过this,这恰好是我到目前为止发现的唯一与我的特定问题最接近的相关问题,但是没有任何进展。

请告知。

1 个答案:

答案 0 :(得分:0)

  1. 进行子布局以接受其VM类型,并在父布局中接受常见的VM类型
  2. 在子布局中将其VM转换为普通VM。

这是我的xml

<data>

    <variable
        name="viewModel"
        type="com.mincom.tools.jemoni.ui.main.fragments.jobs.JobsViewModel" />
</data>

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".ui.main.fragments.jobs.JobsFragment">

    <include
        android:id="@+id/toolbar"
        layout="@layout/main_common_toolbar"
        app:viewModel="@{(com.mincom.tools.jemoni.ui.main.BaseToolbarViewModel) viewModel}" />
</LinearLayout>/>