1. Android网络与存储开发全栈指南
作为一名在Android开发领域深耕多年的工程师,我深知网络与存储模块是每个应用的核心支柱。今天,我将系统性地总结现代Android开发中网络与存储的最佳实践,涵盖从基础到架构设计的完整知识体系。这个系列原本包含16篇文章,经过提炼和整合,我将用一篇文章带你掌握所有关键知识点。
2. 网络层架构设计与实现
2.1 Retrofit + OkHttp核心架构
Retrofit和OkHttp的组合已经成为Android网络请求的事实标准。这套组合之所以如此流行,关键在于它完美解决了类型安全、简洁性和扩展性的问题。
// 典型API接口定义 interface UserApiService { @GET("users/{id}") suspend fun getUser(@Path("id") userId: String): Response<User> @POST("users") suspend fun createUser(@Body user: User): Response<Unit> }Retrofit的注解系统让API定义变得极其直观,而底层基于OkHttp则提供了强大的网络能力。在实际项目中,我通常会这样组织网络层:
- API接口层:定义所有网络请求接口
- 数据转换层:处理JSON序列化/反序列化
- 拦截器层:实现认证、日志、重试等通用逻辑
- Repository层:统一管理数据源
2.2 OkHttp深度配置
OkHttp的强大之处在于它的可配置性。以下是一个生产环境可用的OkHttpClient配置示例:
fun createOkHttpClient(context: Context): OkHttpClient { return OkHttpClient.Builder() .addInterceptor(AuthInterceptor()) // 认证拦截器 .addInterceptor(LoggingInterceptor()) // 日志拦截器 .addInterceptor(RetryInterceptor()) // 重试拦截器 .cache(Cache(context.cacheDir, 10 * 1024 * 1024)) // 10MB缓存 .connectTimeout(30, TimeUnit.SECONDS) .readTimeout(30, TimeUnit.SECONDS) .writeTimeout(30, TimeUnit.SECONDS) .connectionPool(ConnectionPool(5, 5, TimeUnit.MINUTES)) .build() }特别说明几个关键配置:
- 连接池:复用TCP连接,减少握手开销
- 超时设置:根据业务需求调整,API密集型应用可适当缩短
- 缓存配置:合理使用缓存可以显著提升性能
2.3 网络层最佳实践
- 统一错误处理:使用密封类封装网络结果
sealed class NetworkResult<out T> { data class Success<T>(val data: T) : NetworkResult<T>() data class Error(val code: Int, val message: String) : NetworkResult<Nothing>() object Loading : NetworkResult<Nothing>() }- Repository模式:统一管理数据源
class UserRepository @Inject constructor( private val apiService: UserApiService, private val userDao: UserDao ) { fun getUser(userId: String): Flow<NetworkResult<User>> { // 实现离线优先策略 } }- 协程使用:避免回调地狱
viewModelScope.launch { userRepository.getUser(userId).collect { result -> when(result) { is NetworkResult.Loading -> showLoading() is NetworkResult.Success -> showUser(result.data) is NetworkResult.Error -> showError(result.message) } } }3. 数据存储全面解决方案
3.1 数据存储方案选型
Android提供了多种数据存储方案,每种都有其适用场景:
| 方案 | 数据类型 | 性能 | 适用场景 | 推荐度 |
|---|---|---|---|---|
| DataStore | Key-Value/Proto | ⭐⭐⭐⭐ | 用户设置 | ⭐⭐⭐⭐⭐ |
| Room | 结构化数据 | ⭐⭐⭐⭐⭐ | 复杂数据 | ⭐⭐⭐⭐⭐ |
| SharedPreferences | Key-Value | ⭐⭐ | 简单配置(已过时) | ⭐⭐ |
| 文件存储 | 任意数据 | ⭐⭐⭐ | 大文件 | ⭐⭐⭐⭐ |
3.2 Room数据库最佳实践
Room是Android官方推荐的ORM库,使用起来非常方便:
@Database(entities = [User::class], version = 1) abstract class AppDatabase : RoomDatabase() { abstract fun userDao(): UserDao } @Dao interface UserDao { @Query("SELECT * FROM user WHERE id = :userId") fun getUser(userId: String): Flow<User?> @Insert(onConflict = OnConflictStrategy.REPLACE) suspend fun insertUser(user: User) }实际使用中的几个技巧:
- 使用
Flow实现数据观察 - 合理设置
onConflict策略 - 复杂查询考虑使用
@RawQuery
3.3 DataStore替代SharedPreferences
DataStore是SharedPreferences的现代替代品:
val Context.userPreferencesDataStore: DataStore<Preferences> by preferencesDataStore( name = "user_prefs" ) val USER_NAME_KEY = stringPreferencesKey("user_name") suspend fun saveUserName(context: Context, name: String) { context.userPreferencesDataStore.edit { prefs -> prefs[USER_NAME_KEY] = name } } val userNameFlow: Flow<String> = context.userPreferencesDataStore.data .map { prefs -> prefs[USER_NAME_KEY] ?: "" }DataStore的优势:
- 异步API避免ANR
- 类型安全
- 支持协程和Flow
3.4 加密存储方案
对于敏感数据,必须使用加密存储:
val masterKey = MasterKey.Builder(context) .setKeyScheme(MasterKey.KeyScheme.AES256_GCM) .build() val sharedPreferences = EncryptedSharedPreferences.create( context, "secret_shared_prefs", masterKey, EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM )加密存储要点:
- 密钥管理使用Android Keystore
- 加密SharedPreferences适合小数据
- 大文件使用EncryptedFile
4. 缓存策略与性能优化
4.1 多级缓存架构
典型的Android应用应该实现三级缓存:
- 内存缓存:使用LruCache
- 磁盘缓存:使用DiskLruCache
- 网络数据:最终数据源
class ImageCacheManager(context: Context) { private val memoryCache = LruCache<String, Bitmap>(maxMemory / 8) private val diskCache = DiskLruCache.open(cacheDir, 1, 1, 50 * 1024 * 1024) suspend fun getImage(url: String): Bitmap? { // 1. 检查内存缓存 // 2. 检查磁盘缓存 // 3. 网络请求 } }4.2 图片加载优化
图片加载是性能优化的重点:
- 使用专业库:Glide或Coil
- 内存缓存:合理设置缓存大小
- 图片压缩:根据显示尺寸加载
- 大图处理:使用子采样
// Coil示例 imageView.load("https://example.com/image.jpg") { crossfade(true) placeholder(R.drawable.placeholder) transformations(CircleCropTransformation()) }4.3 大文件传输
大文件传输需要特殊处理:
- 分片上传:将大文件分成小块
- 断点续传:记录上传进度
- 进度显示:提供用户反馈
@Multipart @POST("upload") suspend fun uploadFile( @Part file: MultipartBody.Part, @Part("md5") md5: RequestBody, @Part("chunk") chunk: RequestBody, @Part("chunks") chunks: RequestBody ): Response<UploadResult>5. 常见问题与解决方案
5.1 网络请求超时
问题现象:
java.net.SocketTimeoutException: timeout解决方案:
- 适当增加超时时间
- 添加重试机制
- 优化服务器响应
class RetryInterceptor(private val maxRetry: Int = 3) : Interceptor { override fun intercept(chain: Chain): Response { var attempt = 0 var response: Response? = null while (attempt < maxRetry) { try { response = chain.proceed(chain.request()) if (response.isSuccessful) return response } catch (e: IOException) { if (attempt == maxRetry - 1) throw e } attempt++ Thread.sleep(1000L * attempt) } return response!! } }5.2 内存泄漏
排查工具:
- Android Studio Profiler
- LeakCanary
常见场景:
- Activity/Fragment被长生命周期对象持有
- 未取消的网络请求
- 静态集合持有View引用
解决方案:
// 使用ViewModel @HiltViewModel class UserViewModel @Inject constructor( private val repository: UserRepository ) : ViewModel() { // ViewModel自动处理生命周期 } // Fragment中使用viewLifecycleOwner override fun onViewCreated(view: View, savedInstanceState: Bundle?) { viewLifecycleOwner.lifecycleScope.launch { viewModel.user.collect { user -> updateUI(user) } } }5.3 数据同步冲突
场景:
- 离线修改与服务器数据冲突
- 多设备同步问题
解决方案:
- 使用乐观锁
- 实现冲突解决策略
- 提供用户解决界面
data class User( @PrimaryKey val id: String, val name: String, @ColumnInfo(name = "update_time") val updateTime: Long, @ColumnInfo(name = "is_dirty") val isDirty: Boolean = false ) // 同步时比较updateTime fun syncUser(local: User, remote: User): User { return if (local.updateTime > remote.updateTime) { local.copy(isDirty = false) } else { remote.copy(isDirty = false) } }6. 架构设计进阶
6.1 分层架构设计
典型的Android应用应该采用清晰的分层架构:
Presentation Layer (UI) ↓ Domain Layer (Use Cases) ↓ Data Layer (Repository) ↙ ↘ Local Remote每层的职责:
- 表现层:处理UI和用户交互
- 领域层:包含业务逻辑
- 数据层:管理数据源
6.2 模块化设计
大型项目应该采用模块化设计:
- 按功能拆分模块
- 基础模块提供通用能力
- 动态特性模块支持按需加载
:app :feature:home :feature:profile :feature:settings :core:network :core:database :core:utils6.3 测试策略
完善的测试策略应该包含:
- 单元测试:测试业务逻辑
- 集成测试:测试模块交互
- UI测试:测试用户流程
// 示例单元测试 @Test fun `getUser should emit loading then success when network request succeeds`() = runTest { val repository = UserRepository( apiService = mockApiService, userDao = mockUserDao ) coEvery { mockApiService.getUser(any()) } returns testUser val result = repository.getUser("1").first() assertTrue(result is NetworkResult.Loading) }7. 学习路径建议
7.1 初学者路径(0-2个月)
第1-2周:网络基础
- Retrofit基本使用
- OkHttp核心概念
- 简单API调用
第3-4周:数据存储
- Room基础CRUD
- DataStore使用
- 文件存储基础
第5-8周:综合实战
- 实现完整功能
- 添加缓存策略
- 基础性能优化
7.2 进阶路径(2-6个月)
架构设计
- 分层架构实现
- 模块化设计
- 依赖注入
性能优化
- 内存优化
- 网络优化
- 启动优化
高级主题
- 协程深度使用
- Flow状态管理
- 跨进程通信
在实际项目开发中,网络和存储模块的质量直接影响用户体验和应用稳定性。建议从简单项目开始实践,逐步掌握各种高级特性和优化技巧。遇到问题时,多查阅官方文档和社区讨论,Android开发者社区非常活跃,大多数问题都能找到解决方案。