You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Jetpack Compose中对接API并展示用户数据?

解决Jetpack Compose中从dummyjson获取用户数据并展示的问题

一、修正数据类与API接口的匹配问题

dummyjson的/users接口返回结构包含limit/skip/total/users字段,你生成的数据类ApiDataX需要与接口返回类型统一,重命名为Users:

// 替换原ApiDataX,确保和接口返回类型一致
data class Users(
    val limit: Int,
    val skip: Int,
    val total: Int,
    val users: List<User>
)

二、修复API接口路径

Retrofit的baseUrl已包含末尾斜杠,接口注解中的路径不能加开头斜杠,否则会覆盖baseUrl:

interface UserService{
    @GET("users/{id}") // 去掉开头的/
    suspend fun getUser(@Path("id") id :Int): User

    @GET("users") // 去掉开头的/
    suspend fun getAllUsers():Users
}

三、完善ViewModel与Repository解耦

ViewModel不应直接调用API,通过Repository实现解耦,同时添加状态管理处理加载、成功、错误场景:

class UserViewModel(
    private val repository: UserRepository = UserRepository(UserApi.retrofitService)
) : ViewModel() {
    // 用StateFlow适配Compose的状态收集
    private val _uiState = MutableStateFlow<UserUiState>(UserUiState.Loading)
    val uiState: StateFlow<UserUiState> = _uiState.asStateFlow()

    init {
        fetchAllUsers()
    }

    private fun fetchAllUsers() {
        viewModelScope.launch {
            try {
                val usersResponse = repository.getAllUsers()
                _uiState.value = UserUiState.Success(usersResponse.users)
            } catch (e: Exception) {
                _uiState.value = UserUiState.Error(e.message ?: "加载失败")
            }
        }
    }
}

// 定义UI状态,覆盖全场景
sealed class UserUiState {
    object Loading : UserUiState()
    data class Success(val users: List<User>) : UserUiState()
    data class Error(val message: String) : UserUiState()
}

四、集成ViewModel到Compose UI

修改Screen组件,根据ViewModel状态展示对应内容,并传递真实用户数据到Item:

@Composable
fun Screen() {
    val viewModel: UserViewModel = viewModel()
    val uiState by viewModel.uiState.collectAsStateWithLifecycle() // 安全收集生命周期感知状态

    Surface(modifier = Modifier.fillMaxSize()){
        Column(verticalArrangement = Arrangement.spacedBy(10.dp)){
            Spacer(Modifier.height(10.dp))
            Head()
            
            when(uiState) {
                UserUiState.Loading -> {
                    Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
                        CircularProgressIndicator()
                    }
                }
                is UserUiState.Success -> {
                    LazyColumn(modifier = Modifier.padding(15.dp, 10.dp)){
                        items((uiState as UserUiState.Success).users) { user ->
                            Item(user = user)
                        }
                    }
                }
                is UserUiState.Error -> {
                    Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
                        Text(text = (uiState as UserUiState.Error).message, color = Color.Red)
                    }
                }
            }
        }
    }
}

五、更新Item组件展示真实数据

使用网络图片加载用户头像(需添加Coil依赖),并显示真实用户名:

// 先在build.gradle(Module)添加Coil依赖
// implementation("io.coil-kt:coil-compose:2.5.0")

@Composable
fun Item(user: User){
    Box(
        modifier = Modifier
            .fillMaxWidth()
            .padding(10.dp)
    ){
        Row(
            horizontalArrangement = Arrangement.spacedBy(50.dp),
            verticalAlignment = Alignment.CenterVertically
        ){
            AsyncImage(
                model = user.image,
                contentDescription = "${user.firstName} ${user.lastName}",
                modifier = Modifier
                    .size(75.dp)
                    .clip(CircleShape),
                placeholder = painterResource(id = R.drawable.habesha_guy_11),
                error = painterResource(id = R.drawable.habesha_guy_11)
            )
            Column(verticalArrangement = Arrangement.spacedBy(5.dp)){
                Text(
                    text = "${user.firstName} ${user.lastName}",
                    fontFamily = FontFamily.SansSerif,
                    fontWeight = FontWeight(500)
                )
                Button(
                    onClick = {},
                    contentPadding = PaddingValues(horizontal = 40.dp, vertical = 0.dp),
                    modifier = Modifier
                        .border(1.dp, Color.Red, RectangleShape)
                        .height(30.dp),
                    colors = buttonColors(backgroundColor = Color.Transparent),
                    elevation = elevation(
                        defaultElevation = 0.dp,
                        pressedElevation = 0.dp,
                        disabledElevation = 0.dp,
                        hoveredElevation = 0.dp,
                        focusedElevation = 0.dp
                    )
                ){
                    Text(text = "Follow", color = Color.Red)
                }
            }
        }
    }
}

六、修复MainActivity

在setContent中调用Screen组件:

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MemberListTheme {
                Screen()
            }
        }
    }
}

七、添加网络权限

在AndroidManifest.xml中添加网络访问权限:

<uses-permission android:name="android.permission.INTERNET" />

内容的提问来源于stack exchange,提问作者Yimiy Yussef

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 15:39:20