Recently, our company executives introduced coroutines into the project. We have introduced coroutines to you before. If you are not sure, you can take a look at the previous article.

Kotlin – Coroutines

Today I’m going to tell you a little bit about coroutines. Retrofit has native support for coroutines since version 2.6, so using coroutines + Retrofit can shorten our code and speed up our application development.

Although, many masters are already very familiar with this technique, in case of students are not familiar with it?

The target

For simplicity, let’s use Github’s official Api to query the list of repositories that are officially returned.

If you have studied the source code for the official Paging Demo, you will find this code familiar, as a large part of the code comes from the Demo.

First, introduce dependencies

Versions of coroutines and Retrofit:

dependencies {
    implementation 'org. Jetbrains. Kotlinx: kotlinx coroutines -- core: 1.4.2'
    implementation "Org. Jetbrains. Kotlinx: kotlinx coroutines - android: 1.4.2." "
    implementation 'com. Squareup. Retrofit2: retrofit: 2.9.0'
    implementation 'com. Squareup. Retrofit2: converter - gson: 2.9.0'
    implementation 'com. Squareup. Okhttp3: logging - interceptor: 4.0.0'
}
Copy the code

Use Retrofit

Create an interface:

interface GithubApi {
    @GET("search/repositories? sort=stars")
    suspend fun searchRepos(
        @Query("q") query: String.@Query("page") page: Int.@Query("per_page") itemsPerPage: Int
    ): RepoSearchResponse
}
Copy the code

There are two differences with Retrofit:

  1. You have to put it in front of the functionsuspendThe modifier
  2. Use the type we need to return directly, not on the packageCall<T>orObservable<T>

RepoSearchResponse is the returned data:

data class RepoSearchResponse(
    @SerializedName("total_count") val total: Int = 0.@SerializedName("items") val items: List<Repo> = emptyList()
)

data class Repo(
    @SerializedName("id") val id: Long.@SerializedName("name") val name: String,
    @SerializedName("full_name") val fullName: String,
    @SerializedName("description") valdescription: String? .@SerializedName("html_url") val url: String,
    @SerializedName("stargazers_count") val stars: Int.@SerializedName("forks_count") val forks: Int.@SerializedName("language") val language: String?
)
Copy the code

The following steps are consistent with what we normally do with Retrofit:

  1. To create aOkHttpClient
  2. To create aRetrofit
  3. Returns the interface created above

Code:

interface GithubApi {
    / /... The code is omitted

    companion object {
        private const val BASE_URL = "https://api.github.com/"

        fun createGithubApi(a): GithubApi {
            val logger = HttpLoggingInterceptor()
            logger.level = HttpLoggingInterceptor.Level.BASIC

            val client = OkHttpClient.Builder()
                    .addInterceptor(logger)
                    .sslSocketFactory(SSLSocketClient.getSSLSocketFactory(),
                            object : X509TrustManager {
                                override fun checkClientTrusted(
                                        chain: Array<X509Certificate>,
                                        authType: String
                                ) {}
                                override fun checkServerTrusted(
                                        chain: Array<X509Certificate>,
                                        authType: String
                                ) {}
                                override fun getAcceptedIssuers(a): Array<X509Certificate> {
                                    return arrayOf()
                                }
                            })
                    .hostnameVerifier(SSLSocketClient.getHostnameVerifier())
                    .build()
            return Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    .client(client)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build()
                    .create(GithubApi::class.java)
        }
    }
}
Copy the code

Because the interface is an Https request, you need to add ssl-ignoring authentication, and everything else is the same.

Use coroutines to request

Initialize RecyclerView code will not put, relatively simple:

class MainActivity : AppCompatActivity() {
    val scope = MainScope()
    private val mAdapter by lazy {
        MainAdapter()
    }

    override fun onCreate(savedInstanceState: Bundle?). {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        / /... Initialize RecyclerView
        fetchData()
    }

    private fun fetchData(a){
        scope.launch {
            try {
                val result = GithubApi.createGithubApi().searchRepos("Android".0.20)
                if(result ! =null && !result.items.isNullOrEmpty()){
                    mAdapter.submitList(result.items)
                }
            }catch (e: Exception){
                e.printStackTrace()
            }
        }
    }

    override fun onDestroy(a) {
        super.onDestroy()
        scope.cancel()
    }
}
Copy the code

The most convenient part of the coroutine is to eliminate the threading step and use synchronous code to handle time-consuming asynchronous network requests.

Note that there is no extension library for KTX that uses Lifecycle so the Lifecycle of the coroutine scope will have to be released ourselves. In the above code I started a coroutine in onCreate and then cancelled the task in onDestroy. In case of memory leaks.

conclusion

The convenience of coroutines + Retrofit is to use synchronous code to handle asynchronous network requests, minus network callbacks in Retrofit or request callbacks in RxJava + Retrofit.

Wonderful content

If you think this article is good, “like” is the biggest encouragement to the author ~

Technology more than, the article has material, concern public number nine heart said, a high quality good article every week, and nine hearts in Dachang road side by side.