當前位置:網站首頁>[譯] 2019 年的 Android 網絡 —— Retrofit 與 Kotlin 協程(1)
[譯] 2019 年的 Android 網絡 —— Retrofit 與 Kotlin 協程(1)
2022-01-27 06:49:09 【wq221aas】
//OkhttpClient for building http request url
private val tmdbClient = OkHttpClient().newBuilder()
.addInterceptor(authInterceptor)
.build()
fun retrofit() : Retrofit = Retrofit.Builder()
.client(tmdbClient)
.baseUrl(“https://api.themoviedb.org/3/”)
.addConverterFactory(MoshiConverterFactory.create())
.addCallAdapterFactory(CoroutineCallAdapterFactory())
.build()
val tmdbApi : TmdbApi = retrofit().create(TmdbApi::class.java)
}
看一下我們在 ApiFactory.kt 文件中做了什麼。
- 首先,我們創建了一個用以給所有請求添加 api_key 參數的網絡攔截器,名為 authInterceptor。
- 然後我們用 OkHttp 創建了一個網絡客戶端,並添加了 authInterceptor。
- 接下來,我們用 Retrofit 將所有內容連接起來構建 Http 請求的構造器和處理器。此處我們加入了之前創建好的網絡客戶端、基礎 URL、一個轉換器和一個適配器工廠。 首先是 MoshiConverter,用以輔助 JSON 解析並將響應的 JSON 轉化為 Kotlin 數據類,如有需要,可進行選擇性解析。 第二個是 CoroutineCallAdaptor,它的類型是 Retorofit2 中的
CallAdapter.Factory
,用於處理 Kotlin 協程中的Deferred
。 - 最後,我們只需將 TmdbApi 類(下節中創建) 的一個引用傳入之前建好的 retrofit 類中就可以創建我們的 tmdbApi。
探索 Tmdb API
調用 /movie/popular 接口我們得到了如下響應。該響應中返回了 results,這是一個 movie 對象的數組。這正是我們關注的地方。
{
“page”: 1,
“total_results”: 19848,
“total_pages”: 993,
“results”: [
{
“vote_count”: 2109,
“id”: 297802,
“video”: false,
“vote_average”: 6.9,
“title”: “Aquaman”,
“popularity”: 497.334,
“poster_path”: “/5Kg76ldv7VxeX9YlcQXiowHgdX6.jpg”,
“original_language”: “en”,
“original_title”: “Aquaman”,
“genre_ids”: [
28,
14,
878,
12
],
“backdrop_path”: “/5A2bMlLfJrAfX9bqAibOL2gCruF.jpg”,
“adult”: false,
“overview”: “Arthur Curry learns that he is the heir to the underwater kingdom of Atlantis, and must step forward to lead his people and be a hero to the world.”,
“release_date”: “2018-12-07”
},
{
“vote_count”: 625,
“id”: 424783,
“video”: false,
“vote_average”: 6.6,
“title”: “Bumblebee”,
“popularity”: 316.098,
“poster_path”: “/fw02ONlDhrYjTSZV8XO6hhU3ds3.jpg”,
“original_language”: “en”,
“original_title”: “Bumblebee”,
“genre_ids”: [
28,
12,
878
],
“backdrop_path”: “/8bZ7guF94ZyCzi7MLHzXz6E5Lv8.jpg”,
“adult”: false,
“overview”: “On the run in the year 1987, Bumblebee finds refuge in a junkyard in a small Californian beach town. Charlie, on the cusp of turning 18 and trying to find her place in the world, discovers Bumblebee, battle-scarred and broken. When Charlie revives him, she quickly learns this is no ordinary yellow VW bug.”,
“release_date”: “2018-12-15”
}
]
}
因此現在我們可以根據該 JSON 創建我們的 Movie 數據類和 MovieResponse 類。
// Data Model for TMDB Movie item
data class TmdbMovie(
val id: Int,
val vote_average: Double,
val title: String,
val overview: String,
val adult: Boolean
)
// Data Model for the Response returned from the TMDB Api
data class TmdbMovieResponse(
val results: List
)
//A retrofit Network Interface for the Api
interface TmdbApi{
@GET(“movie/popular”)
fun getPopularMovie(): Deferred<Response>
}
TmdbApi 接口:
創建了數據類後,我們創建 TmdbApi 接口,在前面的小節中我們已經將其引用添加至 retrofit 構建器中。在該接口中,我們添加了所有必需的 API 調用,如有必要,可以給這些調用添加任意參數。例如,為了能够根據 id 獲取一部電影,我們在接口中添加了如下方法:
interface TmdbApi{
@GET(“movie/popular”)
fun getPopularMovies() : Deferred<Response>
@GET(“movie/{id}”)
fun getMovieById(@Path(“id”) id:Int): Deferred<Response>
}
最後,進行網絡調用
接著,我們最終發出一個用以獲取所需數據的請求,我們可以在 DataRepository 或者 ViewModel 或者直接在 Activity 中進行此調用。
密封 Result 類
這是用來處理網絡響應的類。它可能成功返回所需的數據,也可能發生异常而出錯。
sealed class Result {
data class Success(val data: T) : Result()
data class Error(val exception: Exception) : Result()
}
構建用來處理 safeApiCall 調用的 BaseRepository
open class BaseRepository{
suspend fun safeApiCall(call: suspend () -> Response, errorMessage: String): T? {
val result : Result = safeApiResult(call,errorMessage)
var data : T? = null
when(result) {
is Result.Success ->
data = result.data
is Result.Error -> {
Log.d(“1.DataRepository”, “$errorMessage & Exception - ${result.exception}”)
}
}
return data
}
private suspend fun <T: Any> safeApiResult(call: suspend ()-> Response, errorMessage: String) : Result{
val response = call.invoke()
if(response.isSuccessful) return Result.Success(response.body()!!)
return Result.Error(IOException(“Error Occurred during getting safe Api result, Custom ERROR - $errorMessage”))
}
}
構建 MovieRepository
class MovieRepository(private val api : TmdbApi) : BaseRepository() {
fun getPopularMovies() : MutableList?{
//safeApiCall is defined in BaseRepository.kt (https://gist.github.com/navi25/67176730f5595b3f1fb5095062a92f15)
val movieResponse = safeApiCall(
call = {api.getPopu
larMovie().await()},
errorMessage = “Error Fetching Popular Movies”
)
return movieResponse?.results.toMutableList();
}
}
創建 ViewModel 來獲取數據
class TmdbViewModel : ViewModel(){
private val parentJob = Job()
private val coroutineContext: CoroutineContext
get() = parentJob + Dispatchers.Default
private val scope = CoroutineScope(coroutineContext)
private val repository : MovieRepository = MovieRepository(ApiFactory.tmdbApi)
val popularMoviesLiveData = MutableLiveData<MutableList>()
fun fetchMovies(){
scope.launch {
val popularMovies = repository.getPopularMovies()
popularMoviesLiveData.postValue(popularMovies)
}
}
fun cancelAllRequests() = coroutineContext.cancel()
}
在 Activity 中使用 ViewModel 更新 UI
class MovieActivity : AppCompatActivity(){
private lateinit var tmdbViewModel: TmdbViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_movie)
class MovieActivity : AppCompatActivity(){
private lateinit var tmdbViewModel: TmdbViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_movie)
版權聲明
本文為[wq221aas]所創,轉載請帶上原文鏈接,感謝
https://cht.chowdera.com/2022/01/202201270649094721.html
邊欄推薦
猜你喜歡
隨機推薦
- uniapp上傳圖片及組件傳值
- 瑞利年金險資金保障安全嗎?收益高不高啊?
- 華為手機USB連不上電腦的解决方法
- Flutter 2,移動金融應用開發
- 關於st25系列NFC標簽簡單介紹及st25TV系列用於門禁讀取時的注意事項總結
- 關於用ffmpeg轉手機視頻發現視頻長寬倒了的問題
- 函數 / 類模板--模板2
- 數組中的第k個最大的元素--優先級隊列、排序、堆、排序
- 單片機實例27——ADC0809A/D轉換器基本應用技術(硬件電路圖+匯編程序+C語言程序)
- Collection集合的學習
- 一場面試結束,某度員工從事Android 5年為何還是初級工程師?
- 3本書閱讀筆記【人月神話-Go語言實戰-研發能力持續成長路線】01
- PHP垃圾回收機制
- 【電子技術】什麼是LFSR?
- 死鎖?如何定比特到死鎖?如何修複死鎖?(jps和jstack兩個工具)
- 快樂寒假 22/01/20
- image
- 噴程序員?SURE?
- LDO分壓電阻計算小工具
- 面試之求一串字符串中每個字符的出現次數
- 【ISO15765_UDS&OBD診斷】-01-概述
- 【Mysql上分之路】第九篇:Mysql存儲引擎
- RHCE 第一次作業
- 2021.10.16我的第一篇博客:一切皆有可能!
- CTA-敏感行為-讀取IMEI
- 面試被問怎麼排查平時遇到的系統CPU飆高和頻繁GC,該怎麼回答?
- nuxt項目總結-綜合
- 自然語言處理學習筆記(一)
- C語言第一課
- 各比特大佬,Spark的重點難點系列暫時更新完畢
- 基於 esbuild 的 universal bundler 設計
- XCTFre逆向(四):insanity
- 理解什麼是真正的並發數
- JVM腦圖
- 【Pytorch(四)】學習如何使用 PyTorch 讀取並處理數據集
- 函數棧幀的創建與銷毀
- 構建神經網絡- 手寫字體識別案例
- 多模態生成模型ERNIE-VILG
- kotlin不容忽視的小細節
- 備戰一年,終於斬獲騰訊T3,我堅信成功是可以複制的