error: attribute android:onProgressChanged not found. error: failed linking file resources

error: attribute android:onProgressChanged not found. error: failed linking file resources

我正在尝试处理 SeekBaronProgressChange 事件。我已将 android:onProgressChanged="onSeekBarChanged" 添加到 xml 布局文件并在我的 Activity kotlin 文件中添加函数:

fun onSeekBarChanged(view: View) {
    Log.d(TAG, "on SeekBarChanged")
}

但编译器抛出以下错误:

Android resource linking failed /home/radek/AndroidStudioProjects/TestMediaStore/app/build/intermediates/incremental/mergeDebugResources/stripped.dir/layout/activity_songfile_list.xml:37: error: attribute android:onProgressChanged not found. error: failed linking file resources.

我做错了什么?

编辑: 这也适用于来自不同侦听器的其他事件属性,例如:

我的布局:

<?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">
    <data>
        <variable name="viewModel" type="com.example.testmediastore.MyViewModel"/>
    </data>
<androidx.coordinatorlayout.widget.CoordinatorLayout    
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true"
        tools:context=".SongFileListActivity">

    <com.google.android.material.appbar.AppBarLayout
            android:id="@+id/app_bar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:theme="@style/AppTheme.AppBarOverlay">

        <androidx.appcompat.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:popupTheme="@style/AppTheme.PopupOverlay"/>

    </com.google.android.material.appbar.AppBarLayout>

    <FrameLayout
            android:id="@+id/frameLayout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior">
        <include layout="@layout/songfile_list"/>
    </FrameLayout>

    <SeekBar
            android:layout_width="match_parent"
            android:layout_height="wrap_content" android:id="@+id/seekbar_playback"
            android:progress="@{viewModel.playerProgress}"
            android:max="@{viewModel.playerProgressMax}"
            android:onProgressChanged="onSeekBarChanged"
            app:layout_behavior="@string/bottom_sheet_behavior"/>

    <fragment
            android:layout_width="wrap_content"
            android:layout_height="@dimen/play_control_height"
            android:name="com.example.testmediastore.PlayControlFragment"
            android:id="@+id/fragment"
            android:layout_gravity="bottom|center"/>

</androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout>

这是完全错误的:android:onProgressChanged="onSeekBarChanged"

正确的方法是:

android:onProgressChanged="@{viewModel::onSeekBarChanged}"

fun onSeekBarChanged(SeekBar seekBar, int progress, boolean fromUser) {
    Log.d(TAG, "on SeekBarChanged")
}

android:onProgressChanged="@{() -> viewModel.onSeekBarChanged()}"

fun onSeekBarChanged() {
    Log.d(TAG, "on SeekBarChanged")
}

第一个解决方案称为方法引用 (documentation)。该方法的签名应与相应侦听器方法的签名相同。在我的例子中是 onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) 来自 SeekBar.OnSeekBarChangeListener

第二种方法称为listener bindings。你可以省略方法的参数。但是注意return值:

If the event you are listening to returns a value whose type isn't void, your expressions must return the same type of value as well. For example, if you want to listen for the long click event, your expression should return a boolean.

onProgressChanged 的 return 值是 void (Kotlin Unit) 所以以上不适用。