如何在Helper类中优雅架构实现HealthConnect Client?
HealthConnect封装类的优化实现方案
问题1:避免重复实例化HealthConnectClient
原代码中同时使用by lazy初始化和checkAvailability内的重复创建,造成冗余实例。优化思路:
- 将
healthConnectClient改为可空类型,仅在确认HealthConnect可用时初始化 - 移除
lazy初始化逻辑,统一在可用性检查后完成实例创建 - 对外提供安全的客户端获取方法,附带可用性二次校验避免空指针
优化后核心代码片段
class HealthConnectManager(private val context: Context) { private var healthConnectClient: HealthConnectClient? = null val PERMISSIONS = setOf( HealthPermission.getReadPermission(HeartRateRecord::class), HealthPermission.getWritePermission(HeartRateRecord::class), HealthPermission.getReadPermission(StepsRecord::class), HealthPermission.getWritePermission(StepsRecord::class) ) init { checkAvailability() } private fun checkAvailability() { if (HealthConnectClient.isProviderAvailable(context)) { healthConnectClient = HealthConnectClient.getOrCreate(context) } else { Toast.makeText(context, "Health Connect未安装,请前往应用商店下载", Toast.LENGTH_LONG).show() val marketIntent = Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=com.google.android.apps.healthdata")) marketIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) context.startActivity(marketIntent) } } // 对外提供安全的客户端获取入口 fun getClient(): HealthConnectClient? { return healthConnectClient.takeIf { HealthConnectClient.isProviderAvailable(context) } } }
问题2:权限处理的优雅实现
权限请求依赖ActivityResultContract与Activity上下文,权限状态检查为挂起函数,分两部分优化:
1. 权限状态检查(hasAllPermissions)
修复原代码中未定义hcClient的问题,添加协程调度优化:
suspend fun hasAllPermissions(permissions: Set<HealthPermission> = PERMISSIONS): Boolean { return withContext(Dispatchers.IO) { val client = getClient() ?: return@withContext false val grantedPermissions = client.permissionController.getGrantedPermissions(permissions) permissions.all { grantedPermissions.contains(it) } } }
该函数需在协程作用域(如lifecycleScope.launch)中调用,无需Activity上下文。
2. 权限请求逻辑
由于PermissionController.createRequestPermissionResultContract()必须与Activity的registerForActivityResult绑定,Helper类仅需提供Contract实例和权限集合,由Activity完成注册与请求发起:
Helper类中保留Contract提供方法
fun getPermissionRequestContract(): ActivityResultContract<Set<HealthPermission>, Set<HealthPermission>> { return androidx.health.connect.client.PermissionController.createRequestPermissionResultContract() }
MainActivity中使用示例
class MainActivity : AppCompatActivity() { private lateinit var hcManager: HealthConnectManager private lateinit var permissionLauncher: androidx.activity.result.ActivityResultLauncher<Set<HealthPermission>> override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) hcManager = HealthConnectManager(this) // 注册权限请求Launcher permissionLauncher = registerForActivityResult(hcManager.getPermissionRequestContract()) { grantedPermissions -> lifecycleScope.launch { if (hcManager.hasAllPermissions()) { Toast.makeText(this@MainActivity, "所有权限已授予", Toast.LENGTH_SHORT).show() readHealthData() } else { Toast.makeText(this@MainActivity, "部分权限未授予,功能受限", Toast.LENGTH_SHORT).show() } } } // 检查权限并发起请求 lifecycleScope.launch { if (!hcManager.hasAllPermissions()) { permissionLauncher.launch(hcManager.PERMISSIONS) } else { readHealthData() } } } private suspend fun readHealthData() { val client = hcManager.getClient() ?: return // 此处添加HealthConnect数据读写逻辑,比如读取步数、心率 Toast.makeText(this, "开始读取健康数据", Toast.LENGTH_SHORT).show() } }
可选优化:Helper类深度封装权限请求(需注意内存泄漏)
若希望Helper类更深度封装权限逻辑,可传入Activity并使用弱引用避免泄漏:
class HealthConnectManager(private val activity: Activity) { private val weakActivity = WeakReference(activity) private var healthConnectClient: HealthConnectClient? = null // ... 其他代码 fun requestPermissions(onResult: (Set<HealthPermission>) -> Unit) { val currentActivity = weakActivity.get() ?: return val launcher = currentActivity.registerForActivityResult(getPermissionRequestContract()) { onResult(it) } launcher.launch(PERMISSIONS) } }
此方式需在Activity的onCreate生命周期内调用权限请求方法,避免生命周期不匹配问题。
完整优化后的HealthConnectManager代码
import android.content.Context import android.content.Intent import android.net.Uri import android.widget.Toast import androidx.activity.result.contract.ActivityResultContract import androidx.health.connect.client.HealthConnectClient import androidx.health.connect.client.permission.HealthPermission import androidx.health.connect.client.records.HeartRateRecord import androidx.health.connect.client.records.StepsRecord import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext class HealthConnectManager(private val context: Context) { private var healthConnectClient: HealthConnectClient? = null val PERMISSIONS = setOf( HealthPermission.getReadPermission(HeartRateRecord::class), HealthPermission.getWritePermission(HeartRateRecord::class), HealthPermission.getReadPermission(StepsRecord::class), HealthPermission.getWritePermission(StepsRecord::class) ) init { checkAvailability() } private fun checkAvailability() { if (HealthConnectClient.isProviderAvailable(context)) { healthConnectClient = HealthConnectClient.getOrCreate(context) } else { Toast.makeText(context, "Health Connect未安装,请前往应用商店下载", Toast.LENGTH_LONG).show() val marketIntent = Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=com.google.android.apps.healthdata")) marketIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) context.startActivity(marketIntent) } } fun getClient(): HealthConnectClient? { return healthConnectClient.takeIf { HealthConnectClient.isProviderAvailable(context) } } suspend fun hasAllPermissions(permissions: Set<HealthPermission> = PERMISSIONS): Boolean { return withContext(Dispatchers.IO) { val client = getClient() ?: return@withContext false val grantedPermissions = client.permissionController.getGrantedPermissions(permissions) permissions.all { grantedPermissions.contains(it) } } } fun getPermissionRequestContract(): ActivityResultContract<Set<HealthPermission>, Set<HealthPermission>> { return androidx.health.connect.client.PermissionController.createRequestPermissionResultContract() } }
内容的提问来源于stack exchange,提问作者Kinematikk
相关产品推荐
相关产品推荐

