0

I'm trying to handle SeekBar's onProgressChange event. I've added android:onProgressChanged="onSeekBarChanged" to xml layout file and function in my Activity kotlin file:

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

but compiler throwing following with error:

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.

What am I doing wrong?

Edit: This is also applicable to other event attributes from different listeners like:

  • android:onLongClick
  • android:onStartTrackingTouch
  • android:onCheckedChanged
  • android:onTextChanged

My layout:

<?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>
Radek Daniluk
  • 405
  • 6
  • 14
  • Possible duplicate of https://stackoverflow.com/questions/54449179/android-resource-linking-failed-when-i-deployment-target – Masum Mar 05 '19 at 04:42
  • @Masum My `compileSdkVersion` and `targetSdkVersion` is set to 28 in app/build.gradle. I even tried `minSdkVersion 28` but error still exist. BTW where I can find more info on minimum required sdk of attributes like `onProgressChanged` – Radek Daniluk Mar 05 '19 at 08:46
  • Change your `minSdkVersion` and try it with 19. – Masum Mar 05 '19 at 08:53
  • @Masum I tried `minSdkVersion` 19, 18 and 28 with invalidating caches and restarting Anadroid Studio but it doesn't work. – Radek Daniluk Mar 05 '19 at 09:10
  • Also see this. : https://stackoverflow.com/questions/24510219/what-is-the-difference-between-min-sdk-version-target-sdk-version-vs-compile-sd. – Masum Mar 05 '19 at 09:10
  • add your gradle in your question. – Masum Mar 05 '19 at 09:12

1 Answers1

0

This was totally wrong: android:onProgressChanged="onSeekBarChanged"

Correct way is:

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

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

OR

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

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

The first solution is called method references (documentation). Signature of the method should be the same as signature of the corresponding listener's method. In my case it was onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) from SeekBar.OnSeekBarChangeListener

Second method is called listener bindings. And you can omit method's parameters. But pay attention to return value:

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's return value is void (Kotlin Unit) so above is not applicable.

Radek Daniluk
  • 405
  • 6
  • 14