开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第7天,点击查看活动详情
继续《Android编程权威指南》第 24 章,本章应用叫 PhotoGallery,现在继续将应用完善好。
九、挑战练习:自定义Gson反序列化器
这里是在说,我们的网络请求响应数据包的时候,包含了多层嵌套数据,然后让我们实现一个自定义反序列化器,把外层的 JSON 数据剔除。
接下来就是补充完整书中的提示代码:
class PhotoDeserializer : JsonDeserializer<PhotoResponse>{
lateinit var photos : PhotoResponse
override fun deserialize(json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext?): PhotoResponse {
val photoJsonObject = json?.asJsonObject
val gson = Gson()
return gson.fromJson(photoJsonObject, PhotoResponse::class.java)
}
}
FlickrApi.kt:
fun fetchPhotos(): Call<PhotoDeserializer>
FlickrFetchr.kt:
init {
val gsonPhotoDeserializer = GsonBuilder()
.registerTypeAdapter(PhotoResponse::class.java, PhotoDeserializer())
.create()
val httpClientBuilder: OkHttpClient.Builder = OkHttpClient.Builder()
httpClientBuilder
.addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
val retrofit = Retrofit.Builder()
.client(httpClientBuilder.build())
.baseUrl("https://www.flickr.com/")
// .addConverterFactory(GsonConverterFactory.create(GsonBuilder().setLenient().create()))
.addConverterFactory(GsonConverterFactory.create(gsonPhotoDeserializer))
// .addConverterFactory(MoshiConverterFactory.create(Moshi.Builder().addLast(KotlinJsonAdapterFactory()).build()))
.build()
flickrApi = retrofit.create(FlickrApi::class.java)
}
fun fetchPhotos(): LiveData<List<GalleryItem>> {
val responseLiveData: MutableLiveData<List<GalleryItem>> = MutableLiveData()
val flickrRequest: Call<PhotoDeserializer> = flickrApi.fetchPhotos()
val repository = Repository()
repository.addFlickrCall(flickrRequest)
flickrRequest.enqueue(object : Callback<PhotoDeserializer> {
override fun onResponse(call: Call<PhotoDeserializer>, response: Response<PhotoDeserializer>) {
Log.d(TAG, "Response received : ${response.body()}")
val photoDeserializer: PhotoDeserializer? = response.body()
val photoResponse: PhotoResponse? = photoDeserializer?.photos
var galleryItems: List<GalleryItem> = photoResponse?.galleryItems ?: mutableListOf()
galleryItems = galleryItems.filterNot { it.url.isBlank() }
responseLiveData.value = galleryItems
}
override fun onFailure(call: Call<PhotoDeserializer>, t: Throwable) {
Log.e(TAG, "Failed to fetch photos", t)
if (call.isCanceled){
Log.e(TAG, "request Canceled")
}
}
})
return responseLiveData
}
运行成功,结果是一样的。
十、挑战练习:分页
本章是说 getList 接口,默认就是返回一页 100 条数据,此接口还有个 page 参数,可以用来返回第二页、第三页等更多页的数据,「一般在我们实际项目中,还会有个 limit 参数,告诉后台一页返回多少条数据」,然后书中推荐我们研究下 Jetpack 分页库,不过项目中由于我引入了一个 RecyclerView Adapter 的库,叫 BaseRecyclerViewAdapterHelper.
用它来做加载更多分页请求非常方便,具体实践就看下官方的实现方式吧。
由于要传个参数 page,因此 ViewModel 还需要稍微做下修改,手动去请求的啦,不用让它初始化就立马做一次请求。
然后书中推荐 Jecpack 分页库,关于分页库 Paging2 官方地址:
developer.android.com/topic/libra…
待我再研究一下再直接补充代码提交到 Github Demo 中。
十一、挑战练习:动态调整网格列
此章节作业要求就是,横屏的时候动态调整网格列数,使横屏的时候显示更多列标题。
然后本章给了个提示,简单实现就是再不同的设备配置或屏幕尺寸提供整数修饰资源,整数修饰资源放在 res/values 目录下,不过这种方式也有个劣势,它其实并不准确,不太好确定网割列分粒度,只能是凭经验多测试几次。
然后另外还有个提示就是,在 fragment 的视图创建就计算并设置好网格列数,注意不能在 onCreateView() 中计算网格列数,因为这个时候 RecyclerView 大小还没确定,建议实现 ViewTreeObserver.OnGlobalLayoutListener 监听器方法和计算列数的 onGlobalLayout() 函数,然后使用 addGoGlobalLayoutListener() 把监听器添加给 RecyclerView 视图。
提示很明显了,好好调试吧。
其他
PhotoGallery 项目 Demo 地址:
🌈关注我吖~❤️
公众号:妮K妮K妮