5.14

从网络请求到数据持久化的全流程实践
在完成 TodoList 应用的基础架构后,我们需要为其添加网络数据同步和本地持久化功能。本文将结合 Java 安卓开发中的网络请求库与 Room 数据库,实现一个完整的 "云同步 TodoList" 应用,探讨如何在安卓环境中处理异步数据交互与离线缓存策略。
一、网络请求实战:Retrofit 与协程的完美结合
Android 开发中,Retrofit是最主流的网络请求库,其设计思想与 Java 后端的 Feign 客户端高度相似:

// 定义API接口(类似Feign接口)
interface TodoApi {
@GET("todos")
Call<List> getTodos();

@POST("todos")  
Call<TodoItem> addTodo(@Body TodoItem todo);  

@PUT("todos/{id}")  
Call<TodoItem> updateTodo(@Path("id") String id, @Body TodoItem todo);  

@DELETE("todos/{id}")  
Call<Void> deleteTodo(@Path("id") String id);  

}

// 配置Retrofit客户端(类似Java的RestTemplate配置)
class ApiClient {
private val baseUrl = "https://jsonplaceholder.typicode.com/"
private lateinit var api: TodoApi

fun getApi(): TodoApi {  
    if (!::api.isInitialized) {  
        val client = OkHttpClient.Builder()  
            .connectTimeout(15, TimeUnit.SECONDS)  
            .readTimeout(20, TimeUnit.SECONDS)  
            .writeTimeout(20, TimeUnit.SECONDS)  
            .build()  

        val retrofit = Retrofit.Builder()  
            .baseUrl(baseUrl)  
            .client(client)  
            .addConverterFactory(GsonConverterFactory.create())  
            .build()  

        api = retrofit.create(TodoApi::class.java)  
    }  
    return api  
}  

}

// 在ViewModel中使用Retrofit(结合协程处理异步)
class TodoViewModel(application: Application) : AndroidViewModel(application) {
private val repository = TodoRepository(TodoDatabase.getDatabase(application).todoDao())
val todos: LiveData<List> = repository.allTodos
private val api = ApiClient().getApi()

fun syncWithServer() {  
    // 使用协程避免阻塞主线程(类似Java的CompletableFuture)  
    viewModelScope.launch {  
        try {  
            // 先获取远程数据  
            val response = api.getTodos().execute()  
            if (response.isSuccessful && response.body() != null) {  
                // 清空本地数据并插入远程数据  
                repository.clearAll()  
                repository.insertAll(response.body()!!)  
            }  
        } catch (e: Exception) {  
            // 网络异常时不做处理,使用本地缓存  
            Log.e("TodoViewModel", "Sync error: ${e.message}")  
        }  
    }  
}  

}

二、数据持久化:Room 数据库与缓存策略
Android 的Room库是基于 SQLite 的 ORM 框架,设计思想类似 Java 的 JPA/Hibernate:
// 定义数据实体(类似JPA的Entity)
@Entity(tableName = "todos")
data class TodoItem(
@PrimaryKey(autoGenerate = true)
val id: Long = 0,
val title: String,
val description: String = "",
val isCompleted: Boolean = false,
val serverId: String? = null, // 远程服务器ID,用于同步
val createTime: Long = System.currentTimeMillis(),
val lastUpdateTime: Long = System.currentTimeMillis()
)

// 定义DAO接口(类似JPA的Repository)
@Dao
interface TodoDao {
@Query("SELECT * FROM todos ORDER BY createTime DESC")
fun getAll(): LiveData<List>

@Insert(onConflict = OnConflictStrategy.REPLACE)  
suspend fun insert(todo: TodoItem): Long  

@Insert  
suspend fun insertAll(todos: List<TodoItem>)  

@Update  
suspend fun update(todo: TodoItem)  

@Delete  
suspend fun delete(todo: TodoItem)  

@Query("DELETE FROM todos")  
suspend fun clearAll()  

}

// 定义数据库类(类似JPA的EntityManagerFactory)
@Database(entities = [TodoItem::class], version = 1)
abstract class TodoDatabase : RoomDatabase() {
abstract fun todoDao(): TodoDao

companion object {  
    @Volatile  
    private var instance: TodoDatabase? = null  

    fun getDatabase(context: Context): TodoDatabase {  
        return instance ?: synchronized(this) {  
            instance ?: buildDatabase(context).also { instance = it }  
        }  
    }  

    private fun buildDatabase(context: Context): TodoDatabase {  
        return Room.databaseBuilder(  
            context.applicationContext,  
            TodoDatabase::class.java,  
            "todo_database"  
        )  
            .fallbackToDestructiveMigration() // 简化版本升级,实际开发应使用Migration  
            .build()  
    }  
}  

}

// 缓存策略实现(本地优先+定期同步)
class TodoRepository(private val todoDao: TodoDao) {
val allTodos: LiveData<List> = todoDao.getAll()

suspend fun syncWithServer() {  
    // 1. 先获取本地数据展示(本地优先)  
    // 2. 异步获取远程数据并更新本地  
    // 省略具体实现,参考ViewModel中的syncWithServer方法  
}  

}
三、离线缓存策略:安卓开发中的数据一致性方案
在移动应用中,网络不稳定是常态,需设计合理的离线缓存策略:
本地优先模式
界面优先展示本地 Room 数据库中的数据,避免空白页面(类似 Java 后端的 Cache-Aside 模式)。
在ViewModel中使用LiveData监听本地数据变化,确保 UI 实时更新。
延迟同步机制
当网络不可用时,将本地修改暂存至 Room,待网络恢复后自动同步(类似 Java 的消息队列重试机制)。
使用WorkManager实现后台同步任务,即使应用退出也能保证数据最终一致性。
冲突解决策略
为每条数据添加lastUpdateTime时间戳,当本地与远程数据冲突时,以最新更新的版本为准(类似 Java 的乐观锁)。

posted @ 2025-05-14 21:02  Echosssss  阅读(5)  评论(0)    收藏  举报