The foreword 0.

  1. The early days of Android programming. Resource scheduling and release is an inevitable problem. Developers schedule resources in onCreate(), such as making network requests, performing disk I/O operations, and then manually releasing or interrupting resource use in onPause() or onDestory().
  2. LifeCycle is introduced. In order to make LifeCycle monitoring easier, Google has introduced LifeCycle Support Library (later migrated to AndroidX as part of Jetpack) to enable developers to better implement automatic LifeCycle awareness when scheduling resources
  3. Introduction of coroutines. Coroutines in Android rely on The Kotlin language, compile as.class files, and ultimately run on a JVM like virtual machine, so the implementation of coroutines is still thread-based, compared to the native coroutine features of other languages such as Lua and Golang. In layman’s terms, The coroutine in Android is more like a thread pool + thread scheduling framework implemented in Kotlin language, and its concepts of non-blocking programming and suspension are simply to allocate tasks to the thread pool for execution, and send the task results back to the main thread when appropriate, so as to achieve the purpose of not blocking the main thread

1. Introduce dependencies

	// File name: build.gradle(:app)
	/ / coroutines
    implementation 'org. Jetbrains. Kotlinx: kotlinx coroutines - android: 1.4.1'
    // lifecycleScope
    implementation 'androidx. Lifecycle: lifecycle - runtime - KTX: 2.3.0'
    // Retrofit
    implementation 'com. Squareup. Retrofit2: retrofit: 2.9.0'
    implementation 'com. Squareup. Retrofit2: converter - gson: 2.9.0'
Copy the code

After the above dependencies have been added to Gradle and synchronized, we can program using coroutines. For simplicity, we have removed the concept of ViewModel and our business code will be written directly on the Activity/Fragment

2. Simple encapsulation of Retrofit

object RetrofitClient {
	private val okHttpClient: OkHttpClient = OkHttpClient.Builder().build()
    
    var api: APIS = initApi()
    
    fun initApi(a): APIS {
        return Retrofit.Builder()
                .baseUrl(https://xxxx.com/api/)
                .addConverterFactory(GsonConverterFactory.create())
                .client(okHttpClient)
                .build().create(APIS::class.java)
    }
    
	suspend fun <T> httpCall(block: suspend RetrofitClient. () - >ResultBean<T>): ResultBean<T> {
        var resultBean: ResultBean<T> = ResultBean()
        try {
            resultBean = block.invoke(this)}catch (e: Exception) {
            e.printStackTrace()
            // Construct a local result when an error occurs
            resultBean = ResultBean<T>().apply {
                data = null
                code = "1"
                message = if (e is ConnectException) "Network connection is abnormal. Please check your network." else "Abnormal interface request"}}finally {
            return resultBean
        }
    }
}
Copy the code

ResultBean is the format of the network response

class ResultBean<T> {
    var code: String? = null
    var message: String? = null
    var data: T? = null
}
Copy the code

Retrofit API interface classes

interface APIS {
	@POST("getUserInfo")
    suspend fun getUserInfo(@Body request: GetUserInfoRequest): ResultBean<GetUserInfoResult>
}
Copy the code

Request body

class GetUserInfoRequest {
    var token: String = ""
    var userId: String = ""
}
Copy the code

Further, place the httpCall() method in the BaseActivity and BaseFragment

/ / BaseActivity. Kt, BaseFragment. Kt
 	suspend fun <T> httpCall(block: suspend RetrofitClient. () - >ResultBean<T>): ResultBean<T> {
        return RetrofitClient.httpCall(block)
    }
Copy the code

3. Invoke it in the Activity

override fun onCreate(savedInstanceState: Bundle?). {
    super.onCreate(savedInstanceState)
    // ...
    val id = intent.getStringExtra("ID") ?: return
    // Get the current coroutine field and execute it within the current Activity lifecycle. Because lifecycleScope automatically stops the code when onDesotry occurs, there is no need to manually cancel the request or release resources
    lifecycleScope.launchWhenCreated {
    	// Network request to obtain personal information
        val userInfo = httpCall {
            api.getUserInfo(GetUserInfoRequest().apply { this.userId = id })
        }
        // When the coroutine is active and the return code is normal, the user name is displayed on the textView
        if(isActive && userInfo.code ! ="1" ) {
            tvTitle.text = userInfo.data? .userName } } }Copy the code

4. To summarize

As you can see, the coroutine can eliminate callback nesting by writing network calls to be synchronous, up-down instead of “asynchronous, callback”; With integration with LifeCycle, we don’t have to worry about null Pointers, memory leaks, etc. caused by network request exceptions or premature page closure