Android技术咨询:Hilt单例重复构建与仓库网络状态最佳实践
Android技术问题解答
1. 最小API 23项目中,仓库获取网络连接状态的最佳实践
- 用ConnectivityManager.NetworkCallback封装StateFlow
API23开始废弃了网络状态广播,改用ConnectivityManager.registerNetworkCallback监听网络变化更可靠。做一个全局的NetworkStatusManager单例,内部用StateFlow<Boolean>维护网络可用状态:- 在
onAvailable回调里把StateFlow值设为true,onLost时设为false;如果需要区分有效网络(能访问互联网),就在onCapabilitiesChanged里判断NetworkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) - 这个Manager在Application启动时注册回调,退出时注销,避免内存泄漏
- 在
- 仓库里直接用流组合,别自己存状态
别在仓库里搞mNetwork变量存状态,容易因实例重建重置。直接把网络状态流和数据请求流结合,用flatMapLatest自动切换数据源:
这样既不会像用fun getDetails(id: String): Flow<Details> { return networkStatusManager.isConnectedFlow.flatMapLatest { isOnline -> if (isOnline) { // 有网请求远程,同时同步到本地 remoteDataSource.fetchDetails(id).onEach { localDataSource.saveDetails(it) } } else { // 没网直接读取本地数据 localDataSource.getDetails(id) } } }first()那样阻塞,还能实时响应网络变化,比如突然断网时自动切到本地数据 - 权限必备
清单文件中一定要声明ACCESS_NETWORK_STATE权限,否则无法获取网络状态
2. 绑定到SingletonComponent的类被Hilt多次构建的原因排查
先查这几个核心点:
- 绑定注解未配置完整
使用@Binds时,不仅模块要标注@InstallIn(SingletonComponent::class),抽象方法和实现类都得加@Singleton注解:
如果实现类是通过@Module @InstallIn(SingletonComponent::class) abstract class RepoModule { @Binds @Singleton abstract fun bindDetailsRepo(impl: DetailsRepoImpl): DetailsRepo }@Inject构造的,构造函数也要加@Singleton,否则Hilt不会按单例管理 - 存在手动实例化的情况
检查代码中是否有直接val repo = DetailsRepoImpl()的写法,这种手动创建会绕过Hilt的单例机制,导致多实例 - 注入的组件范围冲突
确认仓库是否被注入到了比SingletonComponent更窄的组件(比如ActivityComponent),或者自定义了错误的作用域注解。所有获取仓库实例的地方都要通过Hilt的@Inject或依赖注入方式,别混合手动创建 - 打栈轨迹定位创建来源
在仓库的构造函数中打印栈轨迹,看每次实例化的调用来源:
通过日志里的栈信息,就能明确是Hilt重复注入还是手动创建导致的多实例问题class DetailsRepoImpl @Inject constructor(...) { init { Log.d("RepoDebug", "Repo created", Exception("Stack trace")) } }
内容的提问来源于stack exchange,提问作者Karolis
相关产品推荐
相关产品推荐

