安卓软件开发:手把教Jetpack Compose实现对接接口服务层的开发

2024-10-09 11:07:19 浏览数 (4)

2024年已经过半了,我作为聋人独立开发者,我经常会时不时反思:自己这半年到底进步了多少?在这篇文章里,我分享一个用 Jetpack Compose、Material3和 Kotlin 语言实现对接接口服务层的开发案例。无论你有没有开发经验,相信这篇文章对你会非常有所帮助。

一、项目背景

Jetpack Compose 是一个非常重要的 UI 工具,摆脱了传统 XML 布局的麻烦,实现了声明式 UI 开发。这篇文章详细介绍如何通过 Jetpack Compose 构建一个简单Demo,实现从远程 API 获取数据、显示分类列表的功能。Demo的主要目标是展示如何通过 ViewModel 和 Retrofit 实现接口服务层的对接。

二、项目开发

我开发一个简单的分类Demo,用户可以看到来自远程 API 的分类信息,主要架构如下:

1. ViewModel 是数据存储和逻辑层,负责和网络服务交互提供数据给 UI 层。

2. 通过 Retrofit 从远程 API 获取分类信息。

2.1 核心组件

• MainActivity:负责应用的入口。

• MainViewModel:处理从 API 获取数据的逻辑。

• RecipeScreen 和 CategoryScreen:负责 UI 的显示。

2.3 代码实现

2.3.1 API 接口和数据模型

通过 Retrofit 构建了 API 接口,定义了数据模型用于接收 JSON 响应:

代码语言:java复制
private val retrofit = Retrofit.Builder().baseUrl("https://www.xx.com/api/xx/xx/xx/")
    .addConverterFactory(GsonConverterFactory.create())
    .build()

val recipeService = retrofit.create(ApiService::class.java)

interface ApiService {
    @GET("xx.xx")
    suspend fun getCategories(): CategoriesResponse
}

data class Category(
    val idCategory: String,
    val strCategory: String,
    val strCategoryThumb: String,
    val strCategoryDescription: String
)

data class CategoriesResponse(val categories: List<Category>)

2.3.1.1 解释Code

Retrofit实例:使用Retrofit构建器创建一个Retrofit实例,设置基础URL为https://www.xxxx.com/xx/json/xx/,用Gson转换工厂,可以用postman工具调试。

服务接口:定义了一个名为ApiService的接口,包含名为getCategories的挂起函数,用于异步获取类别信息。

网络请求:getCategories函数通过GET请求访问categories.php接口,返回类型是CategoriesResponse。

2.3.2 ViewModel 和数据逻辑

在 MainViewModel 中,通过 viewModelScope 执行网络请求,使用 mutableStateOf 管理状态:

代码语言:java复制
class MainViewModel : ViewModel() {
    private val mCategorieState = mutableStateOf(RecipeState())
    val categoriesState: State<RecipeState> = mCategorieState

    init {
        fetchCategories()
    }

    private fun fetchCategories() {
        viewModelScope.launch {
            try {
                val response = recipeService.getCategories()
                mCategorieState.value = mCategorieState.value.copy(
                    list = response.categories,
                    loading = false,
                    error = null
                )
            } catch (e: Exception) {
                mCategorieState.value = mCategorieState.value.copy(
                    loading = false,
                    error = "Error fetching Categories ${e.message}"
                )
            }
        }
    }

    data class RecipeState(
        val loading: Boolean = true,
        val list: List<Category> = emptyList(),
        val error: String? = null
    )
}

2.3.3 编写UI

用Jetpack Compose 显示从 API 获取的分类列表。RecipeScreen 是主界面,根据当前的状态显示加载中、错误或分类数据:

代码语言:java复制
@Composable
fun RecipeScreen(modifier: Modifier = Modifier) {
    val recipeViewModel: MainViewModel = viewModel()
    val viewstate by recipeViewModel.categoriesState

    Box(modifier = Modifier.fillMaxSize()) {
        Text(
            text = "@Nim独立开发者",
            color = Color.Black,
            style = TextStyle(fontWeight = FontWeight.Bold),
            fontSize = 36.sp,
            modifier = Modifier.align(Alignment.TopCenter).padding(40.dp)
        )

        when {
            viewstate.loading -> {
                CircularProgressIndicator(modifier = Modifier.align(Alignment.Center))
            }
            viewstate.error != null -> {
                Text(
                    text = "Error:404",
                    color = Color.Red,
                    style = TextStyle(fontWeight = FontWeight.Bold),
                    fontSize = 36.sp,
                    modifier = Modifier.align(Alignment.Center)
                )
            }
            else -> {
                CategoryScreen(categories = viewstate.list)
            }
        }
    }
}

2.3.4 预览图

代码语言:java复制
// 预览,使用假数据
@Preview(showBackground = true)
@Composable
fun PreviewRecipeScreen() {
    val fakeCategories = listOf(
        Category(
            idCategory = "1",
            strCategory = "Data1",
            strCategoryThumb = "",
            strCategoryDescription = "Data1"
        ),
        Category(
            idCategory = "2",
            strCategory = "Data2",
            strCategoryThumb = "",
            strCategoryDescription = "Data2"
        ),
        Category(
            idCategory = "3",
            strCategory = "Data3",
            strCategoryThumb = "",
            strCategoryDescription = "Data3"
        )
    )

    val viewstate = MainViewModel.RecipeState(
        loading = false,
        list = fakeCategories,
        error = null
    )

    Box(modifier = Modifier.fillMaxSize()) {
        Text(
            text = "@Nim独立开发者",
            color = Color.Black,
            style = TextStyle(fontWeight = FontWeight.Bold),
            fontSize = 36.sp,
            modifier = Modifier
                .align(Alignment.TopCenter)
                .padding(40.dp)
        )

        CategoryScreen(categories = viewstate.list)
    }
}

2.3.5 视频演示

视频内容

三、技术难点

3.1 Jetpack Compose 和传统 View 的思维转换

使用 Jetpack Compose 进行 UI 开发是一种全新的方式,它和传统的 XML 布局完全不同。最大的难点在于掌握声明式 UI 编程的思想,习惯用数据驱动UI的变化。

3.2 网络请求的异常处理

如果从远程 API 获取数据时,可能会遇到各种异常(如网络连接失败等)。在 ViewModel 中,通过 try-catch 捕获异常并和行错误处理,把错误信息传递给 UI。

3.3 UI 状态管理

如何高效管理和更新 UI 状态是一个关键问题。使用 mutableStateOf 管理状态可以保证 UI 在数据变化时自动更新。

四、学习笔记

在开发过程中,总结了以下几点:

4.1 状态管理

Jetpack Compose是单一数据源和不可变状态,这种设计思想和 Compose 的声明式编程方式完美契合。

4.2 ViewModel 结合

通过 ViewModel,可以很方便管理应用的生命周期和网络数据请求。

4.3 假数据和状态模拟

假数据:在预览过程中,无法依赖真实的网络请求。所以,手动编写了假数据(如 fakeCategories) @Preview 函数调用,为了在 AS 中进行 UI 预览。

使用假状态:通过模拟 MainViewModel.RecipeState,定义了一个没有加载状态和无错误的预览视图,展示成功获取数据的 UI 状态。所以,虽然没有实际的网络请求,开发者同样可以提前查看UI 布局和设计。

五、总结

这次Demo 用 Jetpack Compose 开发App,编写代码实现了从 API 进行数据交互,还编写了如何假设数据UI的正确显示。

有任何问题欢迎提问,感谢大家阅读 )

0 人点赞