MST

星途 面试题库

面试题:Kotlin在Android性能优化方面的多线程应用

在Android性能优化场景下,使用Kotlin的协程进行多线程任务处理。要求实现一个功能,在主线程发起多个异步网络请求,并在所有请求完成后更新UI,描述设计思路并给出核心代码示例。同时说明协程相比传统线程和AsyncTask的优势。
13.7万 热度难度
编程语言Kotlin

知识考点

AI 面试

面试题答案

一键面试

设计思路

  1. 创建协程作用域:使用CoroutineScope来管理协程的生命周期,通常在ViewModel中创建。
  2. 发起异步网络请求:利用async函数在协程中发起异步网络请求,每个async调用返回一个Deferred对象。
  3. 等待所有请求完成:使用awaitAll函数等待所有Deferred对象完成,即所有网络请求完成。
  4. 更新UI:在所有请求完成后,切换到主线程(通过withContext(Dispatchers.Main))来更新UI。

核心代码示例

假设使用Retrofit进行网络请求,以下是核心代码:

import android.os.Bundle
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import kotlinx.coroutines.*
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.GET

// Retrofit API 接口定义
interface ApiService {
    @GET("example")
    suspend fun getExampleData(): String
}

class MainActivity : AppCompatActivity() {

    private lateinit var viewModel: MainViewModel

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

        viewModel = ViewModelProvider(this).get(MainViewModel::class.java)

        val textView = findViewById<TextView>(R.id.textView)

        viewModel.fetchData().observe(this) { data ->
            textView.text = data
        }
    }
}

class MainViewModel : ViewModel() {

    private val _data = MutableLiveData<String>()
    val data: LiveData<String> get() = _data

    private val retrofit = Retrofit.Builder()
       .baseUrl("https://example.com/")
       .addConverterFactory(GsonConverterFactory.create())
       .build()

    private val apiService = retrofit.create(ApiService::class.java)

    fun fetchData(): LiveData<String> {
        viewModelScope.launch {
            try {
                val deferred1 = async { apiService.getExampleData() }
                val deferred2 = async { apiService.getExampleData() }

                val result1 = deferred1.await()
                val result2 = deferred2.await()

                val combinedResult = result1 + result2

                withContext(Dispatchers.Main) {
                    _data.value = combinedResult
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
        return data
    }
}

协程相比传统线程和AsyncTask的优势

  1. 代码简洁:协程使用更简洁的语法来处理异步操作,通过awaitasync等函数代替传统线程的复杂同步机制和AsyncTask的繁琐回调。
  2. 轻量级:协程是轻量级线程,相比传统线程,创建和销毁的开销更小,适合大量异步任务的场景。
  3. 易于管理:通过CoroutineScope可以方便地管理协程的生命周期,避免内存泄漏等问题。而传统线程在Activity或Fragment销毁时可能需要手动管理线程的停止,AsyncTask也存在类似的生命周期管理问题。
  4. 非阻塞:协程在挂起时不会阻塞线程,能够更高效地利用线程资源,提高应用的响应性。传统线程在执行I/O等操作时可能会阻塞线程,导致UI卡顿。AsyncTask虽然也是异步的,但在处理复杂异步逻辑时不够灵活。