3 Commits
Author SHA1 Message Date
lvmengandClaude Sonnet 4.6 037816c303 fix(activity): 修复协程冗余 start() 调用并收敛方法可见性
- 移除 lifecycleScope.launch 后的 .start(),launch 已自动启动协程
- createBlackNV21Frame 和 emptyFrame 加 private 修饰符,收敛对外可见性

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-03 10:20:37 +08:00
lvmengandClaude Sonnet 4.6 dca9496bee refactor(activity): 全面优化 LoginByFaceActivity 代码质量
- 移除静态 instance 引用,消除潜在内存泄漏风险
- Observer {} 显式包装统一改为 Kotlin lambda 写法
- 匿名 Debouncer 改为成员变量 openDebouncer(修复防抖失效 bug)
- Thread.start() 替换为 lifecycleScope.launch(Dispatchers.IO)
- Arrays.fill() 替换为 Kotlin ByteArray.fill(),移除 Java import
- 清理死字段:regDebouncer、faceUseSwitch、faceFailThreshold、tempUserId
- Java getter 语法统一改为 Kotlin 属性访问
- 移除 protected override、无效 handleLoginSuccess override 等冗余代码
- 顶部添加 @file:Suppress("DEPRECATION") 统一处理废弃 API 警告

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-03 10:18:39 +08:00
lvmengandClaude Sonnet 4.6 08f1963054 refactor(network): 优化 ApiClient 代码,清理死代码并统一懒加载初始化
- 移除未使用的 DEVICE_BASE_URL 中间变量,直接引用 GlobalData.appBaseUrl
- okHttpClient 改为 private,收敛可见性
- retrofit 改为 by lazy,与 apiService 保持一致
- 简化日志拦截器 lambda 写法
- 清除所有注释掉的废弃代码

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-03 09:19:49 +08:00
2 changed files with 64 additions and 96 deletions
@@ -1,3 +1,5 @@
@file:Suppress("DEPRECATION")
package com.sw.platecabinet.activity package com.sw.platecabinet.activity
import android.Manifest import android.Manifest
@@ -10,10 +12,8 @@ import android.util.DisplayMetrics
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.ViewTreeObserver import android.view.ViewTreeObserver
import android.widget.ImageView
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.lifecycle.Observer
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import com.arcsoft.face.ErrorInfo import com.arcsoft.face.ErrorInfo
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
@@ -58,12 +58,13 @@ import com.sw.platecabinet.utils.PlateUtils
import com.sw.platecabinet.utils.RegisterCallbackHandler import com.sw.platecabinet.utils.RegisterCallbackHandler
import com.sw.platecabinet.utils.SoundPoolUtil import com.sw.platecabinet.utils.SoundPoolUtil
import com.sw.platecabinet.utils.SpTool import com.sw.platecabinet.utils.SpTool
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode import org.greenrobot.eventbus.ThreadMode
import timber.log.Timber import timber.log.Timber
import java.io.File import java.io.File
import java.util.Arrays
import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicBoolean
/** /**
@@ -89,22 +90,13 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
companion object { companion object {
private const val TAG = "LoginByFaceActivity" private const val TAG = "LoginByFaceActivity"
private var instance: LoginByFaceActivity? = null
private const val COLLECT_SUCCESS = "collect_success" private const val COLLECT_SUCCESS = "collect_success"
private const val RECOGNIZE_SUCCESS = "recognize_success" private const val RECOGNIZE_SUCCESS = "recognize_success"
private const val NO_PLATE_REMIND = "no_plate_remind"; private const val NO_PLATE_REMIND = "no_plate_remind"
fun goInitActivity() {
instance?.goInitActivity()
}
} }
// private var logList: MutableList<String> = mutableListOf()
// private val logAdapter by lazy { LogAdapter(logList) }
override fun initialize() { override fun initialize() {
instance = this
userViewModel.activeEngine() userViewModel.activeEngine()
initArcViewModel() initArcViewModel()
@@ -174,7 +166,7 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
private var rgbFaceRectTransformer: FaceRectTransformer? = null private var rgbFaceRectTransformer: FaceRectTransformer? = null
private val livenessType = LivenessType.RGB private val livenessType = LivenessType.RGB
private var openRectInfoDraw = false private var openRectInfoDraw = false
private val regDebouncer = Debouncer(3000)
private val leftDebouncer = Debouncer(30*1000) private val leftDebouncer = Debouncer(30*1000)
private var registerHandler: RegisterCallbackHandler? = null private var registerHandler: RegisterCallbackHandler? = null
@@ -213,7 +205,7 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
} }
} }
} }
recognizeViewModel.ftInitCode.observe(this, Observer { ftInitCode: Int? -> recognizeViewModel.ftInitCode.observe(this) { ftInitCode: Int? ->
if (ftInitCode != ErrorInfo.MOK) { if (ftInitCode != ErrorInfo.MOK) {
val error: String? = getString( val error: String? = getString(
R.string.specific_engine_init_failed, "ftEngine", R.string.specific_engine_init_failed, "ftEngine",
@@ -222,8 +214,8 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
Timber.e("ftInitCode observe = $error") Timber.e("ftInitCode observe = $error")
ToastUtils.showToast(error) ToastUtils.showToast(error)
} }
}) }
recognizeViewModel.frInitCode.observe(this, Observer { frInitCode: Int? -> recognizeViewModel.frInitCode.observe(this) { frInitCode: Int? ->
if (frInitCode != ErrorInfo.MOK) { if (frInitCode != ErrorInfo.MOK) {
val error: String? = getString( val error: String? = getString(
R.string.specific_engine_init_failed, "frEngine", R.string.specific_engine_init_failed, "frEngine",
@@ -232,8 +224,8 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
Timber.e("frInitCode observe = $error") Timber.e("frInitCode observe = $error")
ToastUtils.showToast(error) ToastUtils.showToast(error)
} }
}) }
recognizeViewModel.flInitCode.observe(this, Observer { flInitCode: Int? -> recognizeViewModel.flInitCode.observe(this) { flInitCode: Int? ->
if (flInitCode != ErrorInfo.MOK) { if (flInitCode != ErrorInfo.MOK) {
val error: String? = getString( val error: String? = getString(
R.string.specific_engine_init_failed, "flEngine", R.string.specific_engine_init_failed, "flEngine",
@@ -242,31 +234,26 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
Timber.e("flInitCode observe = $error") Timber.e("flInitCode observe = $error")
ToastUtils.showToast(error) ToastUtils.showToast(error)
} }
}) }
recognizeViewModel.recognizeConfiguration recognizeViewModel.recognizeConfiguration
.observe(this, Observer { recognizeConfiguration: RecognizeConfiguration? -> .observe(this) { recognizeConfiguration: RecognizeConfiguration? ->
Timber.i("recognizeConfiguration: observe = ${recognizeConfiguration.toString()}") Timber.i("recognizeConfiguration: observe = ${recognizeConfiguration.toString()}")
}) }
recognizeViewModel.recognizeNotice.observe(this, Observer { notice: String? -> recognizeViewModel.recognizeNotice.observe(this) { notice: String? ->
Timber.i("recognizeNotice observe notice = $notice") Timber.i("recognizeNotice observe notice = $notice")
}) }
recognizeViewModel.recognizeUserId.observe(this, Observer { result: CompareResult? -> recognizeViewModel.recognizeUserId.observe(this) { result: CompareResult? ->
loadLogInfo("collectFace,recognizeUserId observe userId = ${result?.faceEntity?.userName}") loadLogInfo("collectFace,recognizeUserId observe userId = ${result?.faceEntity?.userName}")
loadFaceRecognizeResult3(result) loadFaceRecognizeResult3(result)
}) }
recognizeViewModel.drawRectInfoText.observe(this, Observer { info -> recognizeViewModel.drawRectInfoText.observe(this) { info ->
Timber.i("drawRectInfoText observe info = $info") Timber.i("drawRectInfoText observe info = $info")
}) }
} }
/**
* 人脸识别开关,true-loadFaceRecognizeResult2false-loadFaceRecognizeResult
*/
private var faceUseSwitch = true
/** /**
* 识别失败重试次数 * 识别失败重试次数
*/ */
@@ -277,11 +264,6 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
*/ */
private val maxFailCount = 5 private val maxFailCount = 5
/**
* 人脸失败阈值
*/
private val faceFailThreshold = 0.3
/** /**
* 配置阈值,默认值为0.8 * 配置阈值,默认值为0.8
*/ */
@@ -295,8 +277,7 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
binding.tvSimilarValue.text = "$similar${retryFailCount}" binding.tvSimilarValue.text = "$similar${retryFailCount}"
loadLogInfo( loadLogInfo(
"collectFace,recognizeUserId 阈值 success=$faceSuccessThreshold, " + "collectFace,recognizeUserId 阈值 success=$faceSuccessThreshold, similar=$similar, retry=$retryFailCount"
"fail=$faceFailThreshold, similar=$similar, retry=$retryFailCount"
) )
if (similar >= faceSuccessThreshold) { if (similar >= faceSuccessThreshold) {
val userId = result.faceEntity?.userName val userId = result.faceEntity?.userName
@@ -309,7 +290,6 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
return return
} }
// if (similar <= faceFailThreshold || retryFailCount >= maxFailCount) {
if (retryFailCount >= maxFailCount) { if (retryFailCount >= maxFailCount) {
loadLogInfo( loadLogInfo(
"collectFace,recognizeUserId 识别失败,开始采集 similar=$similar, " + "collectFace,recognizeUserId 识别失败,开始采集 similar=$similar, " +
@@ -404,7 +384,7 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
item.updateTime = DateTimeUtils.getDateTimeString() item.updateTime = DateTimeUtils.getDateTimeString()
item.plateNumber = null item.plateNumber = null
plateEnable = false plateEnable = false
Debouncer(5000).debounce { openDebouncer.debounce {
//打开柜子 //打开柜子
PlateUtils.open(this, item.equipmentBoxCode, false) { PlateUtils.open(this, item.equipmentBoxCode, false) {
goInitActivity() goInitActivity()
@@ -416,20 +396,19 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
SpTool.savePlateData(items) SpTool.savePlateData(items)
} }
} }
private val openDebouncer by lazy { Debouncer(5000) }
// private val debouncer by lazy { Debouncer(3000) }
private fun initArcView() { private fun initArcView() {
//在布局结束后才做初始化操作 //在布局结束后才做初始化操作
binding.dualCameraTexturePreviewRgb.getViewTreeObserver().addOnGlobalLayoutListener(this) binding.dualCameraTexturePreviewRgb.viewTreeObserver.addOnGlobalLayoutListener(this)
recognizeViewModel.getCompareResultList().getValue() val list = recognizeViewModel.getCompareResultList().getValue()
loadLogInfo("initArcView:list.size=${list?.size}")
} }
override fun onDestroy() { override fun onDestroy() {
loadLogInfo("onDestroy") loadLogInfo("onDestroy")
instance = null
if (rgbCameraHelper != null) { if (rgbCameraHelper != null) {
rgbCameraHelper!!.release() rgbCameraHelper?.release()
rgbCameraHelper = null rgbCameraHelper = null
} }
@@ -474,7 +453,7 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
layoutParams.width = (measuredHeight * ratio).toInt() layoutParams.width = (measuredHeight * ratio).toInt()
} }
if (scale < 1f) { if (scale < 1f) {
val rgbParam = rgbPreview.getLayoutParams() val rgbParam = rgbPreview.layoutParams
layoutParams.width = (rgbParam.width * scale).toInt() layoutParams.width = (rgbParam.width * scale).toInt()
layoutParams.height = (rgbParam.height * scale).toInt() layoutParams.height = (rgbParam.height * scale).toInt()
} else { } else {
@@ -510,8 +489,8 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
isMirror: Boolean isMirror: Boolean
) { ) {
loadLogInfo("initRgbCamera Rgb onCameraOpened: cameraId = $cameraId, displayOrientation = $displayOrientation") loadLogInfo("initRgbCamera Rgb onCameraOpened: cameraId = $cameraId, displayOrientation = $displayOrientation")
runOnUiThread({ runOnUiThread {
val previewSizeRgb = camera.getParameters().getPreviewSize() val previewSizeRgb = camera.parameters.previewSize
val layoutParams = adjustPreviewViewSize( val layoutParams = adjustPreviewViewSize(
binding.dualCameraTexturePreviewRgb, binding.dualCameraTexturePreviewRgb,
binding.dualCameraTexturePreviewRgb, binding.dualCameraFaceRectView, binding.dualCameraTexturePreviewRgb, binding.dualCameraFaceRectView,
@@ -545,7 +524,7 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
recognizeViewModel.onRgbCameraOpened(camera) recognizeViewModel.onRgbCameraOpened(camera)
recognizeViewModel.setRgbFaceRectTransformer(rgbFaceRectTransformer) recognizeViewModel.setRgbFaceRectTransformer(rgbFaceRectTransformer)
}) }
} }
@RequiresApi(api = Build.VERSION_CODES.Q) @RequiresApi(api = Build.VERSION_CODES.Q)
@@ -607,8 +586,8 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
.previewOn(binding.dualCameraTexturePreviewRgb) .previewOn(binding.dualCameraTexturePreviewRgb)
.cameraListener(cameraListener) .cameraListener(cameraListener)
.build() .build()
rgbCameraHelper!!.init() rgbCameraHelper?.init()
rgbCameraHelper!!.start() rgbCameraHelper?.start()
} }
/** /**
@@ -634,7 +613,7 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
override fun onGlobalLayout() { override fun onGlobalLayout() {
loadLogInfo("onGlobalLayout") loadLogInfo("onGlobalLayout")
binding.dualCameraTexturePreviewRgb.getViewTreeObserver().removeOnGlobalLayoutListener(this) binding.dualCameraTexturePreviewRgb.viewTreeObserver.removeOnGlobalLayoutListener(this)
// 请求权限 // 请求权限
checkCameraPermission() checkCameraPermission()
} }
@@ -644,7 +623,7 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
if (rgbCameraHelper != null && rgbCameraHelper!!.isStopped) { if (rgbCameraHelper != null && rgbCameraHelper!!.isStopped) {
loadLogInfo("collectFace,resumeCamera: ") loadLogInfo("collectFace,resumeCamera: ")
isRecognition = true isRecognition = true
rgbCameraHelper!!.start() rgbCameraHelper?.start()
} else { } else {
//recognizeViewModel.onPreviewFrame(ByteArray(1382400), true) //recognizeViewModel.onPreviewFrame(ByteArray(1382400), true)
@@ -663,27 +642,29 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
* @param height 图像高度(如 1080 * @param height 图像高度(如 1080
* @return 合法的全黑帧字节数组 * @return 合法的全黑帧字节数组
*/ */
fun createBlackNV21Frame(width: Int, height: Int): ByteArray { private fun createBlackNV21Frame(width: Int, height: Int): ByteArray {
val frameSize = width * height val frameSize = width * height
val nv21Data = ByteArray(frameSize * 3 / 2) // NV21 格式长度 = 宽×高×1.5 val nv21Data = ByteArray(frameSize * 3 / 2) // NV21 格式长度 = 宽×高×1.5
// Y 分量(亮度)设为 0(全黑),UV 分量设为 128(默认值) // Y 分量(亮度)设为 0(全黑),UV 分量设为 128(默认值)
// 1. 填充 Y 分量(前 frameSize 个字节) // 1. 填充 Y 分量(前 frameSize 个字节)
Arrays.fill(nv21Data, 0, frameSize, 0.toByte()) // Arrays.fill(nv21Data, 0, frameSize, 0.toByte())
nv21Data.fill(0, 0, frameSize)
// 2. 填充 UV 分量(后 frameSize/2 个字节) // 2. 填充 UV 分量(后 frameSize/2 个字节)
Arrays.fill(nv21Data, frameSize, nv21Data.size, 128.toByte()) // Arrays.fill(nv21Data, frameSize, nv21Data.size, 128.toByte())
nv21Data.fill(128.toByte(), frameSize, nv21Data.size)
return nv21Data return nv21Data
} }
// 调用示例:构造 1920×1080 的全黑帧(长度 1382400 // 调用示例:构造 1920×1080 的全黑帧(长度 1382400
val emptyFrame = createBlackNV21Frame(1920, 1080) private val emptyFrame = createBlackNV21Frame(1920, 1080)
// 传递“空帧” recognizeViewModel.onPreviewFrame(emptyFrame, true) // 传递“空帧” recognizeViewModel.onPreviewFrame(emptyFrame, true)
/** // /**
* 临时用户id // * 临时用户id
*/ // */
private var tempUserId: String = "" // private var tempUserId: String = ""
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
try { try {
@@ -714,7 +695,7 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
isCollectFace = false isCollectFace = false
plateEnable = true plateEnable = true
collectCount = 0 collectCount = 0
tempUserId = "${System.currentTimeMillis()}" // tempUserId = "${System.currentTimeMillis()}"
resumeCamera() resumeCamera()
registerHandler = RegisterCallbackHandler() registerHandler = RegisterCallbackHandler()
@@ -741,7 +722,7 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
private var isFirstOpen = true private var isFirstOpen = true
protected override fun onPause() { override fun onPause() {
pauseCamera() pauseCamera()
super.onPause() super.onPause()
CountDownManager.cancelCountDown() CountDownManager.cancelCountDown()
@@ -752,11 +733,6 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
// recognizeViewModel.onPreviewFrame(emptyFrame, true) // recognizeViewModel.onPreviewFrame(emptyFrame, true)
} }
override fun handleLoginSuccess(equipmentUserInfo: EquipmentUserInfo, isAdmin: Boolean) {
super.handleLoginSuccess(equipmentUserInfo, isAdmin)
// goInitActivity()
}
private fun judgeRecognizeState(): Boolean { private fun judgeRecognizeState(): Boolean {
val rectColor = binding.dualCameraFaceRectView.rectColor val rectColor = binding.dualCameraFaceRectView.rectColor
if (rectColor == RecognizeColor.COLOR_SUCCESS && currentUserId.isNullOrBlank().not() && facePreviewInfoList.isNullOrEmpty().not()) { if (rectColor == RecognizeColor.COLOR_SUCCESS && currentUserId.isNullOrBlank().not() && facePreviewInfoList.isNullOrEmpty().not()) {
@@ -823,14 +799,14 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
loadLogInfo("collectFace,sendFaceData: ----------12,发送人脸数据成功但接口返回为null,faceData=${faceData}") loadLogInfo("collectFace,sendFaceData: ----------12,发送人脸数据成功但接口返回为null,faceData=${faceData}")
return@addUserFace return@addUserFace
} }
Thread { lifecycleScope.launch(Dispatchers.IO) {
saveFaceInfo(faceModel) { saveFaceInfo(faceModel) {
runOnUiThread { runOnUiThread {
Glide.with(this@LoginByFaceActivity).load(imageFile).into(binding.ivCollectPhoto) Glide.with(this@LoginByFaceActivity).load(imageFile).into(binding.ivCollectPhoto)
} }
} }
uploadFaceDebouncer.reset() uploadFaceDebouncer.reset()
}.start() }
} }
} }
@@ -866,7 +842,7 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
private var currentUserId: String? = null private var currentUserId: String? = null
private fun saveFaceInfo(faceModel: UserFaceModel, block:()-> Unit= {}) { private fun saveFaceInfo(faceModel: UserFaceModel, block: () -> Unit = {}) {
try { try {
loadLogInfo("collectFace,saveFaceInfo: ----------8,保存人脸取特征数据-----------") loadLogInfo("collectFace,saveFaceInfo: ----------8,保存人脸取特征数据-----------")
val faceDao = FaceDatabase.getInstance(this).faceDao() val faceDao = FaceDatabase.getInstance(this).faceDao()
@@ -12,37 +12,29 @@ import timber.log.Timber
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
object ApiClient { object ApiClient {
//private const val BASE_URL = "https://vip.shuziweidao.com"
// private const val DEVICE_BASE_URL = "http://device.shuziweidao.com:8889/"
private var DEVICE_BASE_URL = GlobalData.appBaseUrl
// private const val BASE_URL = "http://192.168.1.8:9092"
// private const val TIME_OUT = 30L // 超时时间(秒)
private const val TIME_OUT = 60L // 超时时间(秒)
val okHttpClient = OkHttpClient.Builder() private const val TIME_OUT = 60L // 超时时间(秒)
private val okHttpClient = OkHttpClient.Builder()
.connectTimeout(TIME_OUT, TimeUnit.SECONDS) .connectTimeout(TIME_OUT, TimeUnit.SECONDS)
.readTimeout(TIME_OUT, TimeUnit.SECONDS) .readTimeout(TIME_OUT, TimeUnit.SECONDS)
.writeTimeout(TIME_OUT, TimeUnit.SECONDS) .writeTimeout(TIME_OUT, TimeUnit.SECONDS)
.addNetworkInterceptor(HttpLoggingInterceptor(logger = { .addNetworkInterceptor(HttpLoggingInterceptor { Timber.d("okhttp ==>${it}") }.apply {
Timber.d("okhttp logger ==>${it}") level = if (MyApp.DEBUG) HttpLoggingInterceptor.Level.BODY
}).apply { else HttpLoggingInterceptor.Level.NONE
level = if (MyApp.DEBUG) {
HttpLoggingInterceptor.Level.BODY
} else {
HttpLoggingInterceptor.Level.NONE
}
}) })
.addInterceptor(RequestInterceptor()) .addInterceptor(RequestInterceptor())
.build() .build()
private val retrofit = Retrofit.Builder() private val retrofit by lazy {
.baseUrl(DEVICE_BASE_URL) Retrofit.Builder()
.client(okHttpClient) .baseUrl(GlobalData.appBaseUrl)
.addConverterFactory(GsonConverterFactory.create()) .client(okHttpClient)
// .addCallAdapterFactory(CoroutineCallAdapterFactory()) // 协程适配器 .addConverterFactory(GsonConverterFactory.create())
.build() .build()
}
val apiService: ApiService by lazy { val apiService: ApiService by lazy {
retrofit.create(ApiService::class.java) retrofit.create(ApiService::class.java)
} }
} }