Android Kotlin:PagingSource中invalidate为final无法重写问题求助
解决PagingSource中invalidate方法重写冲突问题
我刚接触Android开发,参考GitHub上一个用Retrofit调用Deezer API的项目,在自己项目里实现时,编写PagingSource类遇到了问题:重写invalidate方法时提示‘PagingSource中的invalidate是final方法,无法重写’;去掉override修饰符后又提示‘invalidate隐藏了父类PagingSource的成员,需要override修饰符’。
我的PagingSource类代码
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() } }
错误提示 : 'invalidate' in 'PagingSource' is final and cannot be overridden
我的gradle配置文件
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 }
问题解决方法
1. 统一Paging依赖版本
你的Paging依赖版本不一致:paging-common-ktx用了3.1.1,而paging-runtime-ktx用了3.0.0-alpha10,这会导致API不兼容。在Paging 3的正式版本中,invalidate()已被标记为final方法,无法重写;旧alpha版本中该方法是非final的,所以参考的旧项目可以重写,但新版本不允许。
修改gradle中的Paging依赖,保持版本一致:
//paging implementation 'androidx.paging:paging-common-ktx:3.1.1' implementation 'androidx.paging:paging-runtime-ktx:3.1.1'
2. 替换重写invalidate的实现
移除重写的invalidate()方法,改用registerInvalidatedCallback监听失效事件,在回调中清除缓存:
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>() private val queryCache = mutableListOf<String>() } init { // 注册失效回调,在PagingSource失效时清除缓存 registerInvalidatedCallback { inMemoryCache.clear() queryCache.clear() } } // ... 其他原有代码保持不变 ... // 移除原来的override invalidate方法 }
3. 额外优化建议
- 伴生对象的静态缓存会在所有PagingRepository实例间共享,可能导致不同查询的数据互相干扰,建议将缓存改为实例变量,或者用查询字符串作为key区分不同缓存。
- 避免用
!!强制解包response.body(),改用空安全处理防止空指针:val body = response.body() ?: return LoadResult.Error(NullPointerException("接口返回内容为空"))
内容的提问来源于stack exchange,提问作者Vũ Minh
相关产品推荐
相关产品推荐

