12

*编辑:要回答我自己的问题,我必须将 EditorViewModel 作为导入添加到外部布局中的父抽象类,并使用app:viewModel="@{((EditorViewModel)viewModel)}将 viewModel 转换为父类“,就是这样!我发誓我不记得以前做过这个演员表……*

我的问题是因为包含的布局定义了一个类型,它是外部布局试图与包含的布局共享的 viewModel 的父抽象类,而不是子具体类。

我已经确认将包含的布局类型更改为子具体类的类型可以解决问题,但是,它应该适用于抽象类类型......

这是我定义 viewModel 变量的方式,这是以下类型中的具体类:

<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:bind="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">

<data>

    <variable
        name="viewModel"
        type="com.ootpapps.gpeofflinedatacollection.viewmodels.EquipmentEditorViewModel" />
</data>
...

几句话之后,我包含了布局,试图从上面共享 viewModel:

<include
            layout="@layout/layout_spinner_location"
            app:viewModel="@{viewModel}" />

在包含的布局中,变量 viewModel 定义如下:

<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bind="http://schemas.android.com/apk/res-auto">

<data>

    <variable
        name="viewModel"
        type="com.ootpapps.gpeofflinedatacollection.viewmodels.EditorViewModel" />
</data>

当然,这里的 EquipmentEditorViewModel 显示它扩展了抽象父类 EditorViewModel(在包含的布局中定义为上面的父类类型):

public class EquipmentEditorViewModel extends EditorViewModel<Equipment> {

我收到的错误是:

****/ 数据绑定错误 ****msg:在 com.ootpapps.gpeofflinedatacollection.databinding.LayoutSpinnerLocationBinding 上找不到参数类型为 com.ootpapps.gpeofflinedatacollection.viewmodels.EquipmentEditorViewModel 的属性“app:viewModel”的设置器。文件:C:\Users\Ryan\AndroidstudioProjects\GPEOfflineDataCollection\app\src\main\res\layout\content_equipment_editor.xml 位置:31:33 - 31:41 ****\数据绑定错误 ****

正如我上面提到的,将 layout_spinner_location 中的类型更改为“EquipmentEditorViewModel”可以修复错误,但是,我需要使用抽象类型才能重新使用此视图,因为它并不总是使用 EquipmentEditorViewModel,有时它需要一个“ ToolEditorViewModel”或“MeasurmentEditorViewModel”,它们都扩展了 EditorViewModel。

非常感谢您的帮助。也许我会很幸运,乔治·芒特会过来。

4

2 回答 2

11

只是为了清楚,如果有人遇到这个。

添加了 3 种解决问题的方法,#3 似乎是赢家

这似乎是新 gradle 3 及更高版本的问题,并出现以下错误:找不到属性“app:viewModel”的设置器

父 xml

<?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">

    <data>

        <variable
            name="viewModel"
            type="com.myapp.android.viewmodel.base.PageWebViewViewModel" />

    </data>

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:animateLayoutChanges="true"
        android:orientation="vertical">

        <WebView
            android:id="@+id/webview_content"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:visibility="@{viewModel.contentVisibility}"
            app:baseUrl="@{null}"
            app:builtInZoomControlsEnabled="@{false}"
            app:cacheMode="@{viewModel.webViewCacheMode}"
            app:data="@{viewModel.webViewData}"
            app:domStorageEnabled="@{true}"
            app:encoding="@{`UTF-8`}"
            app:headers="@{viewModel.headers}"
            app:javaScriptEnabled="@{true}"
            app:loadUrl="@{viewModel.webViewUrl}"
            app:mimeType="@{`text/html; charset=utf-8`}"
            app:webChromeClient="@{viewModel.webChromeClient}"
            app:webInterface="@{viewModel.webInterface}"
            app:webInterfaceName="@{viewModel.webInterfaceName}"
            app:webViewClient="@{viewModel.webViewClient}" />

        <include
            layout="@layout/request_error_view"
            app:viewModel="@{viewModel}" />

        <include
            android:id="@+id/lyt_loading"
            layout="@layout/loading_layout"
            app:viewModel="@{viewModel}" />
    </FrameLayout>
</layout>

包含/子 xml(布局/request_error_view)

<?xml version="1.0" encoding="utf-8"?>
<layout>

    <data>

        <variable
            name="viewModel"
            type="com.myapp.android.viewmodel.base.BaseViewModel" />
    </data>

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/send_request_error_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:layout_gravity="center"
        android:gravity="center"
        android:orientation="vertical"
        android:visibility="@{viewModel.errorVisibility}">

        <TextView
            android:id="@+id/text_error_sending_request"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="@string/error_sending_request"
            android:textColor="@color/window_primary_text"
            android:textSize="@dimen/text_size_large" />

        <Button
            android:id="@+id/button_try_again"
            style="@style/SuperbalistButton.Green.NoInset"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="@dimen/standard_content_margin"
            android:onClick="@{viewModel::onClickReload}"
            android:text="@string/try_again" />
    </LinearLayout>
</layout>

#1 之后(第二个变量方法,似乎不起作用)

父 xml

<?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">

    <data>

        <variable
            name="viewModel"
            type="com.myapp.android.viewmodel.base.PageWebViewViewModel" />

        <variable
            name="viewModelBase"
            type="com.myapp.android.viewmodel.base.BaseViewModel" />
    </data>

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:animateLayoutChanges="true"
        android:orientation="vertical">

        <WebView
            android:id="@+id/webview_content"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:visibility="@{viewModel.contentVisibility}"
            app:baseUrl="@{null}"
            app:builtInZoomControlsEnabled="@{false}"
            app:cacheMode="@{viewModel.webViewCacheMode}"
            app:data="@{viewModel.webViewData}"
            app:domStorageEnabled="@{true}"
            app:encoding="@{`UTF-8`}"
            app:headers="@{viewModel.headers}"
            app:javaScriptEnabled="@{true}"
            app:loadUrl="@{viewModel.webViewUrl}"
            app:mimeType="@{`text/html; charset=utf-8`}"
            app:webChromeClient="@{viewModel.webChromeClient}"
            app:webInterface="@{viewModel.webInterface}"
            app:webInterfaceName="@{viewModel.webInterfaceName}"
            app:webViewClient="@{viewModel.webViewClient}" />

        <include
            layout="@layout/request_error_view"
            app:viewModel="@{viewModelBase}" />

        <include
            android:id="@+id/lyt_loading"
            layout="@layout/loading_layout"
            app:viewModel="@{viewModelBase}" />
    </FrameLayout>
</layout>

#2之后(铸造方法,有效)

父 xml

<?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">

    <data>

        <variable
            name="viewModel"
            type="com.myapp.android.viewmodel.base.PageWebViewViewModel" />
    </data>

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:animateLayoutChanges="true"
        android:orientation="vertical">

        <WebView
            android:id="@+id/webview_content"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:visibility="@{viewModel.contentVisibility}"
            app:baseUrl="@{null}"
            app:builtInZoomControlsEnabled="@{false}"
            app:cacheMode="@{viewModel.webViewCacheMode}"
            app:data="@{viewModel.webViewData}"
            app:domStorageEnabled="@{true}"
            app:encoding="@{`UTF-8`}"
            app:headers="@{viewModel.headers}"
            app:javaScriptEnabled="@{true}"
            app:loadUrl="@{viewModel.webViewUrl}"
            app:mimeType="@{`text/html; charset=utf-8`}"
            app:webChromeClient="@{viewModel.webChromeClient}"
            app:webInterface="@{viewModel.webInterface}"
            app:webInterfaceName="@{viewModel.webInterfaceName}"
            app:webViewClient="@{viewModel.webViewClient}" />

        <include
            layout="@layout/request_error_view"
            app:viewModel="@{((com.myapp.android.viewmodel.base.BaseViewModel) viewModel)}" />

        <include
            android:id="@+id/lyt_loading"
            layout="@layout/loading_layout"
            app:viewModel="@{((com.myapp.android.viewmodel.base.BaseViewModel) viewModel)}" />
    </FrameLayout>
</layout>

#3 之后(导入和转换方法,有效)

父 xml

<?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">

    <data>
        <import type="com.myapp.android.viewmodel.base.BaseViewModel" />
        <variable
            name="viewModel"
            type="com.myapp.android.viewmodel.base.PageWebViewViewModel" />
    </data>

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:animateLayoutChanges="true"
        android:orientation="vertical">

        <WebView
            android:id="@+id/webview_content"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:visibility="@{viewModel.contentVisibility}"
            app:baseUrl="@{null}"
            app:builtInZoomControlsEnabled="@{false}"
            app:cacheMode="@{viewModel.webViewCacheMode}"
            app:data="@{viewModel.webViewData}"
            app:domStorageEnabled="@{true}"
            app:encoding="@{`UTF-8`}"
            app:headers="@{viewModel.headers}"
            app:javaScriptEnabled="@{true}"
            app:loadUrl="@{viewModel.webViewUrl}"
            app:mimeType="@{`text/html; charset=utf-8`}"
            app:webChromeClient="@{viewModel.webChromeClient}"
            app:webInterface="@{viewModel.webInterface}"
            app:webInterfaceName="@{viewModel.webInterfaceName}"
            app:webViewClient="@{viewModel.webViewClient}" />

        <include
            layout="@layout/request_error_view"
            app:viewModel="@{(BaseViewModel) viewModel)}" />

        <include
            android:id="@+id/lyt_loading"
            layout="@layout/loading_layout"
            app:viewModel="@{((BaseViewModel) viewModel)}" />
    </FrameLayout>
</layout>
于 2017-12-18T12:13:46.530 回答
2

此方法完美运行

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <data>
         <variable
            name="viewmodel"
           type="com.myapp.data.ViewModel" />
  </data>
    <include
        android:id="@+id/include"
        layout="@layout/buttons_layout" />

</layout>

按钮布局

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <data>
         <variable
            name="viewmodel"
           type="com.myapp.data.ViewModel" />
  </data>
     <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="@{() -> viewmodel.onClickChangeName()}"
        android:text="Change Name"
        app:layout_constraintTop_toBottomOf="@id/include"
        app:layout_constraintStart_toStartOf="parent"
        />
</layout>

主要活动

lateinit var dataBinding: ActivityMainBinding
lateinit var viewModel: viewModel
dataBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
viewModel = ViewModelProvider(this).get(ViewModel::class.java)
dataBinding.include.viewModel = viewModel
dataBinding.viewModel = viewModel
dataBinding.executePendingBindings()
    
于 2021-06-04T13:43:40.200 回答