preface
- This is an essay, I want to try to write an article.
- I won’t go into the details here, but for more information please refer to Benny’s Blog and Kotlin’s official documentation
Why coroutines
- Coroutines are smaller than threads
Me: Why use coroutines here when you already have Rx? Colleague: Because coroutines are smaller than threads, many can be opened. I:… Why smaller than a thread?
I checked it out and it does say smaller than threads. But look at some source code, thread pool + thread implementation, then began to have doubts, why is the same thread, how is smaller than the thread? Until I read Big Benny’s article explaining why coroutines are called “lightweight threads” it became clear to me. Pass the test and start literally thousands of coroutines without getting OOM or anything else.
- Of course, the most important thing is the code experience. Now Kotlin is becoming more and more common, and various inline functions and operators can almost replace the common Rx operators. So the experience in writing code is relatively good.
(Note: PERSONALLY, I don’t think coroutines make much difference for Android development. The most important thing is to write code and code aesthetics.)
Add dependencies
implementation"Com. Squareup. Retrofit2: retrofit: 2.6.2." "
implementation"Com. Squareup. Retrofit2: converter - gson: 2.6.2." "
// Coroutines
implementation 'org. Jetbrains. Kotlinx: kotlinx coroutines -- core: 1.3.2'
implementation 'org. Jetbrains. Kotlinx: kotlinx coroutines - android: 1.3.2'
Copy the code
Remember to use RetroFIT 2.6.0 or above
Two, prepare the network request interface
- Create the interface
interface GitApi {
@GET("/users/{username}/{module}")
suspend fun repos(
@Path("username") username: String.@Path("module") module: String.@Query("page") currPage: Int
): List<RepoInfo>
@GET("/search/repositories")
suspend fun searchRepos(
@Query("q") key: String.@Query("sort") sort: String? = "updated".@Query("order") order: String? = "desc".@Query("page") currPage: Int
): SearchResponse
}
Copy the code
- Create a Retrofit instance
fun buildRetrofit(a): Retrofit {
builder.addInterceptor(HttpLoggingInterceptor(object : HttpLoggingInterceptor.Logger {
override fun log(message: String) {
Timber.d(message)
}
}).apply {
level = HttpLoggingInterceptor.Level.BODY
}).addInterceptor(object : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val userCredentials = "$username:$password"
val basicAuth =
"Basic ${String(Base64.encode(userCredentials.toByteArray(), Base64.DEFAULT))}"
val original = chain.request()
val requestBuilder = original.newBuilder()
.header("Authorization", basicAuth.trim { it <= ' ' })
val request = requestBuilder.build()
return chain.proceed(request)
}
})
return Retrofit.Builder()
.client(builder.build())
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
}
Copy the code
Use it in ViewModel
Kotlinx. Coroutines. CoroutineScope interface of comments have so a word
Scope
CoroutineScope
viewModelScope
lifecycle
open class BaseViewModel : ViewModel() {
fun <T> request(
onError: (error: Throwable) -> Unit = {}, // Do not need to handle Error can not passexecute: suspend CoroutineScope.() -> T ) { viewModelScope.launch(errorHandler { onError.invoke(it) }) { launch(Dispatchers.IO) { execute() } } }private fun errorHandler(onError: (error: Throwable) -> Unit): CoroutineExceptionHandler {
return CoroutineExceptionHandler { _, throwable ->
Timber.d(throwable)
onError.invoke(throwable)
}
}
}
Copy the code
Call the Request method using the BaseViewModel inheritance.
class RepoViewModel(
private val userRepo: UserDataSource,
private val gitApi: GitApi
) : BaseViewModel() {
private val _reposResult = BaseLiveData<List<RepoInfo>>()
val repoResult: BaseLiveData<List<RepoInfo>>
get() = _reposResult
fun fetchRepos(module: String){ request { userRepo.currUser()? .let {val result = gitApi.repos(it.nickname, module, 1)
_reposResult.update(result)
}
}
}
}
Copy the code
OR
fun fetchRepos(module: String) {
request(
onError = {
// handle error}, execute = { userRepo.currUser()? .let {val result = gitApi.repos(it.nickname, module, 1)
_reposResult.update(result)
}
}
)
}
Copy the code
All that remains is basically the implementation of the logic on the subscription between LiveData and Fragments.
conclusion
I have been studying recently and my understanding is not very deep. Welcome comments and suggestions. Study project address Dithub.