'invalidate' in 'PagingSource' is final and cannot be overridden [Android Kotlin]?

291 Views Asked by At

I've just started in android development. I saw a project on github that use Retrofit to call Deezer Api and I want to implement it to my project but i ran into a trouble in the PagingSource class, here the PagingSource class :

package com.example.myapplication.data.remote.paging

import androidx.paging.PagingSource
import com.example.myapplication.data.models.ResponseData
import com.example.myapplication.data.models.album.Album
import com.example.myapplication.data.models.artist.Artist
import com.example.myapplication.data.models.tracks.Track
import com.example.myapplication.data.remote.paging.PagingDataSource
import com.example.myapplication.data.services.ServiceType
import retrofit2.HttpException
import java.io.IOException
abstract class PagingRepository(
private val query: String,
private val serviceType: ServiceType,
private val pagingDataSource: PagingDataSource
) : PagingSource\<Int, ResponseData\>() {

    companion object {
        private val inMemoryCache =
            mutableListOf<ResponseData>() // (*) we don't care about the object type
        private val queryCache = mutableListOf<String>()
    }
    
    private val startPage = 0
    private val limit = 25
    
    override suspend fun load(params: LoadParams<Int>): LoadResult<Int, ResponseData> {
        val position = params.key ?: startPage
        val apiQuery = query
        return try {
    
            val oldQuery = queryCache.find {
                apiQuery.equals(it, true)
            }
    
            if (oldQuery != null && position == startPage) {
                val validatedResults = resultsValidatedAndSorted(apiQuery)
                LoadResult.Page(
                    data = validatedResults,
                    prevKey = null,
                    nextKey = null
                )
            } else {
                val response = when (serviceType) {
                    ServiceType.Artists -> pagingDataSource.fetchArtist(apiQuery, position * limit, limit)
                    ServiceType.Albums -> pagingDataSource.fetchAlbum(apiQuery, position * limit, limit)
                    ServiceType.Tracks -> pagingDataSource.fetchTrack(apiQuery, position * limit, limit)
                }
                val body = response.body()!!
                val results = response.body()!!.data
    
                queryCache.add(apiQuery)
    
                val shelled = results.map { ResponseData(query = apiQuery, data = it) }
    
                inMemoryCache.addAll(
                    shelled
                )
    
                LoadResult.Page(
                    data = if (position * limit <= body.total) shelled else emptyList(),
                    prevKey = if (position == startPage) null else position - 1,
                    nextKey = if (shelled.isEmpty() || position * limit > body.total) null else position + 1
                )
            }
    
        } catch (exception: IOException) {
            return LoadResult.Error(exception)
        } catch (exception: HttpException) {
            return LoadResult.Error(exception)
        }
    }
    
    private fun resultsValidatedAndSorted(query: String): List<ResponseData> {
        return inMemoryCache.filter {
            it.query.contains(query, true)
        }
    }
    
    override fun invalidate()
    {
        super.invalidate()
        inMemoryCache.clear()
        queryCache.clear()
    }

}

error : 'invalidate' in 'PagingSource' is final and cannot be overridden

Here my gradle file :

plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'com.google.gms.google-services'
id 'kotlin-kapt'
id 'kotlin-android'

    id 'com.google.dagger.hilt.android'
    id 'androidx.navigation.safeargs.kotlin'
    id 'kotlin-parcelize'

}

android {
namespace 'com.example.myapplication'
compileSdk 33

    defaultConfig {
        applicationId "com.example.myapplication"
        minSdk 33
        targetSdk 33
        versionCode 1
        versionName "1.0"
       // buildToolsVersion "30.0.2"
        def secureProps = new Properties()
        if (file("../secure.properties").exists()) {
            file("../secure.properties")?.withInputStream { secureProps.load(it) }
        }
        vectorDrawables.useSupportLibrary = true
        buildConfigField "String", "BASE_URL", (secureProps.getProperty("BASE_URL") ?: "")
        buildConfigField "String", "SECRET", (secureProps.getProperty("SECRET") ?: "")
    
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
    
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        freeCompilerArgs += ["-opt-in=kotlin.RequiresOptIn"] // opt in for experimental functions
        jvmTarget = '1.8'
    }
    buildFeatures {
        viewBinding = true
      dataBinding = true
    }

}

dependencies {
implementation 'androidx.work:work-runtime-ktx:2.8.1'
implementation 'androidx.core:core-ktx:1.9.0'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.8.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'com.google.firebase:firebase-firestore-ktx:24.4.5'
implementation platform('com.google.firebase:firebase-bom:31.3.0')
implementation 'com.google.firebase:firebase-analytics-ktx:21.2.1'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
//paging
implementation 'androidx.paging:paging-common-ktx:3.1.1'
implementation 'androidx.paging:paging-runtime-ktx:3.0.0-alpha10'
//navigation
def nav_version ="2.5.3"
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
implementation "androidx.navigation:navigation-dynamic-features-fragment:$nav_version"

    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.5'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
    //coroutines
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4'
    // - - ViewModel
    implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1'
    implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
    //glide
    implementation 'com.github.bumptech.glide:glide:4.15.1'
    kapt 'com.github.bumptech.glide:compiler:4.15.1'
    //bottomNavigation
    implementation 'com.google.android.material:material:1.8.0'
    //splashscreen
    implementation 'androidx.core:core-splashscreen:1.0.0'
    // -- retrofit
    implementation 'com.squareup.retrofit2:retrofit:2.9.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
    implementation 'com.squareup.okhttp3:logging-interceptor:4.9.0'
    // Lifecycle
    implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
    implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.6.1"
    //implementation "androidx.lifecycle:lifecycle-runtime:2.6.1"
    implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.6.1"
    
    // HILT
    def hilt_version = "2.45"
    implementation "com.google.dagger:hilt-android:$hilt_version"
    kapt "com.google.dagger:hilt-compiler:$hilt_version"
    
    "androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha03"
    kapt "androidx.hilt:hilt-compiler:1.0.0"
    // Timber
    implementation 'com.jakewharton.timber:timber:5.0.1'
    // ExoPlayer
    api "com.google.android.exoplayer:exoplayer-core:2.18.5"
    api "com.google.android.exoplayer:exoplayer-ui:2.18.5"
    api "com.google.android.exoplayer:extension-mediasession:2.18.5"
    
    // Firebase
    implementation 'com.google.firebase:firebase-firestore:24.4.5'
    
    // Firebase Storage KTX
    implementation 'com.google.firebase:firebase-storage-ktx:20.1.0'
    
    // Firebase Coroutines
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.6.4'
    
    
    
    implementation 'androidx.media:media:1.6.0'
    
    implementation 'com.google.firebase:firebase-analytics-ktx:21.2.1'
    // Coil Image Loading Library
    implementation('io.coil-kt:coil:1.1.0')
    // Subtitle supported collapsing toolbar
    implementation 'com.hendraanggrian.material:collapsingtoolbarlayout-subtitle:1.1.0'
    
    // Flow Binding
    implementation 'io.github.reactivecircus.flowbinding:flowbinding-android:0.10.2'
    
    implementation('androidx.preference:preference-ktx:1.1.1')

}
kapt {
correctErrorTypes = true
}

But when I remove the overide fun invalidate() to fun invalidate() it has another error : "'invalidate' hides member of supertype 'PagingSource' and needs 'override' modifier"

1

There are 1 best solutions below

0
kuzdu On

So the reason for the behaviour is that PagingSource is abstract. It is declared like this:

public abstract class PagingSource<Key : Any, Value : Any> {

From an abstract class you can not create a object.

So if you want to call invalidate it is interpret as a final (static) method. You can not override finals. But if you don't write the override modifier you hide the invalidate function from PagingSource. This is not allowed.

To be precise. fun invalidate should have declared as abstract fun invalide() Then you must implement the function via override.

But invalidate() is declared like this and a real implementation in PagingSource

 public fun invalidate() {
   // implementation
 }

I can not solve your code because I don't know what should happen when and so on. If you just need an invalidate which you can call like this:

pagingRepository.invalidate()

Then just create another function like this

pagingRepository.invalidatePaging()

fun invalidatePager() {
  this.invalidate() // this should have the same effect like your planned override
  inMemoryCache.clear()
  queryCache.clear()
} 

But again I don't know enough code and the architecture of your example. If you want to dive deep then do a google lab for paging.