The foreword 0.
- 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().
- 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
- 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