Android翻新NetworkBoundResource返回null

Android翻新NetworkBoundResource返回null,android,kotlin,retrofit,Android,Kotlin,Retrofit,我正在尝试使用改型和NetworkBoundResource()从第三方API检索数据。但是,当此NetworkBoundResource运行时,它返回null 我试图获取的JSON如下所示: { "id":93 "name":"Business" "total":587 "has_next":true &qu

我正在尝试使用改型和NetworkBoundResource()从第三方API检索数据。但是,当此NetworkBoundResource运行时,它返回null

我试图获取的JSON如下所示:

    {
        "id":93
        "name":"Business"
        "total":587
        "has_next":true
        "podcasts":[]
    }
希望有人能帮忙!相关代码如下

Podcasts.kt

@Keep
@Entity(
    tableName = "podcasts"
)
@Parcelize
data class Podcast(
    @PrimaryKey
    @ColumnInfo(name = "id")
    val id: String,
    @ColumnInfo(name = "title")
    val title: String,
    @ColumnInfo(name = "publisher")
    val publisher: String,
    @ColumnInfo(name = "image")
    val image: String,
    @ColumnInfo(name = "thumbnal")
    val thumbnail: String,
    @ColumnInfo(name = "url")
    val url: String,
    @ColumnInfo(name = "total_episodes")
    @Json(name = "total_episodes")
    val total: Int,
    @ColumnInfo(name = "favourite")
    var favourite: Boolean = false,
) : Parcelable

@Entity(
    tableName = "best_podcasts",
    indices = [Index(
        value = ["id"],
        unique = true
    )]
)
data class BestPodcasts(
    @PrimaryKey
    @ColumnInfo(name = "id")
    val id: String,
    @ColumnInfo(name = "podcasts")
    val podcasts: List<Podcast>
)
保持 @实体( tableName=“播客” ) @包裹 数据类播客( @主键 @ColumnInfo(name=“id”) valid:String, @ColumnInfo(name=“title”) val标题:字符串, @ColumnInfo(name=“publisher”) val publisher:String, @ColumnInfo(name=“image”) val image:String, @ColumnInfo(name=“thumbnal”) val缩略图:字符串, @ColumnInfo(name=“url”) val url:String, @ColumnInfo(name=“剧集总数”) @Json(name=“total_剧集”) val总计:整数, @ColumnInfo(name=“收藏夹”) var favorite:Boolean=false, ):可包裹 @实体( tableName=“最佳播客”, 索引=[Index( 值=[“id”], 唯一=真 )] ) 数据类最佳播客( @主键 @ColumnInfo(name=“id”) valid:String, @ColumnInfo(name=“播客”) val播客:列表 ) 网络边界资源

    abstract class NetworkBoundResource<ResultType, RequestType>
    @MainThread constructor(private val appExecutors: AppExecutors) {
        //
        private val result = MediatorLiveData<Resource<ResultType>>()

        init {
            result.value = Resource.loading(null)
            @Suppress("LeakingThis")
            val dbSource = loadFromDb()
            result.addSource(dbSource) { data ->
                result.removeSource(dbSource)
                if (shouldFetch(data)) {
                    fetchFromNetwork(dbSource)
                } else {
                    result.addSource(dbSource) { newData ->
                        setValue(Resource.success(newData))
                    }
                }
            }
        }

        @MainThread
        private fun setValue(newValue: Resource<ResultType>) {
            if (result.value != newValue) {
                result.value = newValue
            }
        }

        private fun fetchFromNetwork(dbSource: LiveData<ResultType>) {
            val apiResponse = createCall()
            // we re-attach dbSource as a new source, it will dispatch its latest value quickly
            result.addSource(dbSource) { newData ->
                setValue(Resource.loading(newData))
            }
            result.addSource(apiResponse) { response ->
                result.removeSource(apiResponse)
                result.removeSource(dbSource)
                when (response) {
                    is ApiSuccessResponse -> {
                        appExecutors.diskIO().execute {
                            saveCallResult(processResponse(response))
                            appExecutors.mainThread().execute {
                                // we specially request a new live data,
                                // otherwise we will get immediately last cached value,
                                // which may not be updated with latest results received from network.
                                result.addSource(loadFromDb()) { newData ->
                                    setValue(Resource.success(newData))
                                }
                            }
                        }
                    }
                    is ApiEmptyResponse -> {
                        appExecutors.mainThread().execute {
                            // reload from disk whatever we had
                            result.addSource(loadFromDb()) { newData ->
                                setValue(Resource.success(newData))
                            }
                        }
                    }
                    is ApiErrorResponse -> {
                        onFetchFailed()
                        result.addSource(dbSource) { newData ->
                            setValue(Resource.error(response.errorMessage, newData))
                        }
                    }
                }
            }
        }

        fun asLiveData() = result as LiveData<Resource<ResultType>>

        @WorkerThread
        protected open fun processResponse(response: ApiSuccessResponse<RequestType>) = response.body

        @WorkerThread
        protected abstract fun saveCallResult(item: RequestType)

        @MainThread
        protected abstract fun shouldFetch(data: ResultType?): Boolean

        @MainThread
        protected abstract fun loadFromDb(): LiveData<ResultType>

        @MainThread
        protected abstract fun createCall(): LiveData<ApiResponse<RequestType>>

        protected open fun onFetchFailed() {
            Log.d("AHHHH", "Fetch failed")
        }
    }
    class RemoteDataSource {
        private val podcastApiService = PodcastApi.retrofitService

        fun downloadBestPodcasts(): LiveData<ApiResponse<BestPodcasts>> {
            return podcastApiService.downloadBestPodcasts()
        }
    }
    private val retrofit = Retrofit.Builder()
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(LiveDataCallAdapterFactory())
        .baseUrl(BASE_URL)
        .build()

    interface WebService {
        @GET("best_podcasts")
        fun downloadBestPodcasts(
            @Header("X-ListenAPI-Key") apiKey: String = BuildConfig.API_KEY,
            @Query("genre") genreId: Int? = null
        ): LiveData<ApiResponse<BestPodcasts>>
    }
抽象类NetworkBoundResource
@主线程构造函数(私有val appExecutors:appExecutors){
//
private val result=MediatorLiveData()
初始化{
result.value=Resource.loading(null)
@抑制(“泄漏此”)
val dbSource=loadFromDb()
result.addSource(dbSource){data->
result.removeSource(dbSource)
if(shouldFetch(数据)){
fetchFromNetwork(dbSource)
}否则{
result.addSource(dbSource){newData->
setValue(资源成功(新数据))
}
}
}
}
@主线
private-fun-setValue(newValue:Resource){
if(result.value!=newValue){
result.value=newValue
}
}
私有网络(dbSource:LiveData){
val apiResponse=createCall()
//我们将dbSource作为一个新源重新连接,它将快速发送其最新值
result.addSource(dbSource){newData->
setValue(资源加载(新数据))
}
result.addSource(apiResponse){response->
result.removeSource(apiResponse)
result.removeSource(dbSource)
何时(回应){
是APIssuccessResponse->{
appExecutors.diskIO().execute{
saveCallResult(processResponse(response))
appExecutors.mainThread().execute{
//我们特别要求提供新的实时数据,
//否则我们将立即获得最后一个缓存值,
//可能不会使用从网络接收的最新结果更新。
result.addSource(loadFromDb()){newData->
setValue(资源成功(新数据))
}
}
}
}
是ApipEmptyResponse->{
appExecutors.mainThread().execute{
//从磁盘重新加载我们所拥有的一切
result.addSource(loadFromDb()){newData->
setValue(资源成功(新数据))
}
}
}
是ApiErrorResponse->{
onFetchFailed()
result.addSource(dbSource){newData->
setValue(Resource.error(response.errorMessage,newData))
}
}
}
}
}
fun asLiveData()=结果为LiveData
@工作线程
受保护的open fun processResponse(响应:APIssuccessResponse)=响应.body
@工作线程
受保护的抽象趣味saveCallResult(项:RequestType)
@主线
受保护的抽象fun shouldFetch(数据:ResultType?):布尔值
@主线
受保护的抽象数据loadFromDb():LiveData
@主线
受保护的抽象调用():LiveData
受保护的open fun onFetchFailed(){
Log.d(“ahhh”,“获取失败”)
}
}
RemoteDataSource

    abstract class NetworkBoundResource<ResultType, RequestType>
    @MainThread constructor(private val appExecutors: AppExecutors) {
        //
        private val result = MediatorLiveData<Resource<ResultType>>()

        init {
            result.value = Resource.loading(null)
            @Suppress("LeakingThis")
            val dbSource = loadFromDb()
            result.addSource(dbSource) { data ->
                result.removeSource(dbSource)
                if (shouldFetch(data)) {
                    fetchFromNetwork(dbSource)
                } else {
                    result.addSource(dbSource) { newData ->
                        setValue(Resource.success(newData))
                    }
                }
            }
        }

        @MainThread
        private fun setValue(newValue: Resource<ResultType>) {
            if (result.value != newValue) {
                result.value = newValue
            }
        }

        private fun fetchFromNetwork(dbSource: LiveData<ResultType>) {
            val apiResponse = createCall()
            // we re-attach dbSource as a new source, it will dispatch its latest value quickly
            result.addSource(dbSource) { newData ->
                setValue(Resource.loading(newData))
            }
            result.addSource(apiResponse) { response ->
                result.removeSource(apiResponse)
                result.removeSource(dbSource)
                when (response) {
                    is ApiSuccessResponse -> {
                        appExecutors.diskIO().execute {
                            saveCallResult(processResponse(response))
                            appExecutors.mainThread().execute {
                                // we specially request a new live data,
                                // otherwise we will get immediately last cached value,
                                // which may not be updated with latest results received from network.
                                result.addSource(loadFromDb()) { newData ->
                                    setValue(Resource.success(newData))
                                }
                            }
                        }
                    }
                    is ApiEmptyResponse -> {
                        appExecutors.mainThread().execute {
                            // reload from disk whatever we had
                            result.addSource(loadFromDb()) { newData ->
                                setValue(Resource.success(newData))
                            }
                        }
                    }
                    is ApiErrorResponse -> {
                        onFetchFailed()
                        result.addSource(dbSource) { newData ->
                            setValue(Resource.error(response.errorMessage, newData))
                        }
                    }
                }
            }
        }

        fun asLiveData() = result as LiveData<Resource<ResultType>>

        @WorkerThread
        protected open fun processResponse(response: ApiSuccessResponse<RequestType>) = response.body

        @WorkerThread
        protected abstract fun saveCallResult(item: RequestType)

        @MainThread
        protected abstract fun shouldFetch(data: ResultType?): Boolean

        @MainThread
        protected abstract fun loadFromDb(): LiveData<ResultType>

        @MainThread
        protected abstract fun createCall(): LiveData<ApiResponse<RequestType>>

        protected open fun onFetchFailed() {
            Log.d("AHHHH", "Fetch failed")
        }
    }
    class RemoteDataSource {
        private val podcastApiService = PodcastApi.retrofitService

        fun downloadBestPodcasts(): LiveData<ApiResponse<BestPodcasts>> {
            return podcastApiService.downloadBestPodcasts()
        }
    }
    private val retrofit = Retrofit.Builder()
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(LiveDataCallAdapterFactory())
        .baseUrl(BASE_URL)
        .build()

    interface WebService {
        @GET("best_podcasts")
        fun downloadBestPodcasts(
            @Header("X-ListenAPI-Key") apiKey: String = BuildConfig.API_KEY,
            @Query("genre") genreId: Int? = null
        ): LiveData<ApiResponse<BestPodcasts>>
    }
类远程数据源{
private val PodcastApi服务=PodcastApi.service
乐趣下载BestPodcast():LiveData{
return podcastApiService.downloadBestPodcasts()
}
}
数据存储库

    class DataRepository(
        private val localDataSource: LocalDataSource,
        private val remoteDataSource: RemoteDataSource,
        private val appExecutors: AppExecutors
    ) {
        fun downloadBestPodcasts(shouldFetch: Boolean): LiveData<Resource<BestPodcasts>> {
            return object :
                NetworkBoundResource<BestPodcasts, BestPodcasts>(appExecutors) {
                override fun saveCallResult(item: BestPodcasts) {
                    localDataSource.insertBestPodcasts(item)
                }

                override fun shouldFetch(data: BestPodcasts?) = data == null || shouldFetch

                override fun loadFromDb(): LiveData<BestPodcasts> =
                    localDataSource.getBestPodcasts()

                override fun createCall() = remoteDataSource.downloadBestPodcasts()
            }.asLiveData()
        }
    }
类数据存储库(
私有val localDataSource:localDataSource,
私有val remoteDataSource:remoteDataSource,
私人val上诉人:上诉人
) {
有趣的下载BestPodcast(shouldFetch:Boolean):LiveData{
返回对象:
NetworkBoundResource(appExecutors){
覆盖有趣的saveCallResult(项目:BestPodcast){
localDataSource.InsertBestPodcast(项目)
}
重写fun shouldFetch(数据:BestPodcasts?=data==null | | shouldFetch)
重写fun loadFromDb():LiveData=
localDataSource.getBestPodcasts()
重写fun createCall()=remoteDataSource.DownloadBestPodcast()
}.asLiveData()
}
}
WebService

    abstract class NetworkBoundResource<ResultType, RequestType>
    @MainThread constructor(private val appExecutors: AppExecutors) {
        //
        private val result = MediatorLiveData<Resource<ResultType>>()

        init {
            result.value = Resource.loading(null)
            @Suppress("LeakingThis")
            val dbSource = loadFromDb()
            result.addSource(dbSource) { data ->
                result.removeSource(dbSource)
                if (shouldFetch(data)) {
                    fetchFromNetwork(dbSource)
                } else {
                    result.addSource(dbSource) { newData ->
                        setValue(Resource.success(newData))
                    }
                }
            }
        }

        @MainThread
        private fun setValue(newValue: Resource<ResultType>) {
            if (result.value != newValue) {
                result.value = newValue
            }
        }

        private fun fetchFromNetwork(dbSource: LiveData<ResultType>) {
            val apiResponse = createCall()
            // we re-attach dbSource as a new source, it will dispatch its latest value quickly
            result.addSource(dbSource) { newData ->
                setValue(Resource.loading(newData))
            }
            result.addSource(apiResponse) { response ->
                result.removeSource(apiResponse)
                result.removeSource(dbSource)
                when (response) {
                    is ApiSuccessResponse -> {
                        appExecutors.diskIO().execute {
                            saveCallResult(processResponse(response))
                            appExecutors.mainThread().execute {
                                // we specially request a new live data,
                                // otherwise we will get immediately last cached value,
                                // which may not be updated with latest results received from network.
                                result.addSource(loadFromDb()) { newData ->
                                    setValue(Resource.success(newData))
                                }
                            }
                        }
                    }
                    is ApiEmptyResponse -> {
                        appExecutors.mainThread().execute {
                            // reload from disk whatever we had
                            result.addSource(loadFromDb()) { newData ->
                                setValue(Resource.success(newData))
                            }
                        }
                    }
                    is ApiErrorResponse -> {
                        onFetchFailed()
                        result.addSource(dbSource) { newData ->
                            setValue(Resource.error(response.errorMessage, newData))
                        }
                    }
                }
            }
        }

        fun asLiveData() = result as LiveData<Resource<ResultType>>

        @WorkerThread
        protected open fun processResponse(response: ApiSuccessResponse<RequestType>) = response.body

        @WorkerThread
        protected abstract fun saveCallResult(item: RequestType)

        @MainThread
        protected abstract fun shouldFetch(data: ResultType?): Boolean

        @MainThread
        protected abstract fun loadFromDb(): LiveData<ResultType>

        @MainThread
        protected abstract fun createCall(): LiveData<ApiResponse<RequestType>>

        protected open fun onFetchFailed() {
            Log.d("AHHHH", "Fetch failed")
        }
    }
    class RemoteDataSource {
        private val podcastApiService = PodcastApi.retrofitService

        fun downloadBestPodcasts(): LiveData<ApiResponse<BestPodcasts>> {
            return podcastApiService.downloadBestPodcasts()
        }
    }
    private val retrofit = Retrofit.Builder()
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(LiveDataCallAdapterFactory())
        .baseUrl(BASE_URL)
        .build()

    interface WebService {
        @GET("best_podcasts")
        fun downloadBestPodcasts(
            @Header("X-ListenAPI-Key") apiKey: String = BuildConfig.API_KEY,
            @Query("genre") genreId: Int? = null
        ): LiveData<ApiResponse<BestPodcasts>>
    }
private val reformation=reformation.Builder()
.addConverterFactor