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

如何在React Native的Android组件(Retrofit+协程+MVVM)获取API数据并传给RN渲染UI?

解决思路与实现步骤

一、Android端:基于MVVM+Retrofit+协程实现数据请求

1. 定义Retrofit API接口与数据实体

先编写Retrofit服务接口,用协程suspend方法发起异步请求,同时定义对应的数据实体类:

// API接口
interface ProductApiService {
    @GET("products")
    suspend fun getAllProducts(): Response<List<Product>>
}

// 商品数据实体
data class Product(
    val id: Int,
    val title: String,
    val price: Double,
    val description: String,
    val category: String,
    val image: String
)

2. 实现Repository层封装请求逻辑

统一处理数据请求的业务逻辑,封装Retrofit调用并返回结果状态:

class ProductRepository(private val apiService: ProductApiService) {
    suspend fun fetchAllProducts(): Result<List<Product>> {
        return try {
            val response = apiService.getAllProducts()
            if (response.isSuccessful) {
                Result.success(response.body() ?: emptyList())
            } else {
                Result.failure(Throwable("请求失败:${response.message()}"))
            }
        } catch (e: Exception) {
            Result.failure(e)
        }
    }
}

3. ViewModel层管理UI状态与协程

借助viewModelScope发起协程请求,用LiveData维护数据状态:

class ProductViewModel(private val repository: ProductRepository) : ViewModel() {
    private val _productsState = MutableLiveData<Result<List<Product>>>()
    val productsState: LiveData<Result<List<Product>>> = _productsState

    fun loadAllProducts() {
        viewModelScope.launch {
            _productsState.value = repository.fetchAllProducts()
        }
    }
}

4. 封装React Native原生模块

创建Native Module暴露给RN调用,内部触发ViewModel的数据请求,将结果转换为RN兼容格式后回调:

class ProductModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
    private lateinit var productViewModel: ProductViewModel

    override fun getName(): String {
        return "ProductModule" // RN中调用的模块名称
    }

    override fun initialize() {
        super.initialize()
        // 初始化Retrofit、Repository与ViewModel(实际项目建议用Hilt依赖注入)
        val retrofit = Retrofit.Builder()
            .baseUrl("你的API基础地址")
            .addConverterFactory(GsonConverterFactory.create())
            .build()
        val apiService = retrofit.create(ProductApiService::class.java)
        val repository = ProductRepository(apiService)
        productViewModel = ProductViewModel(repository)
    }

    // 暴露给RN的异步方法,用Promise返回结果
    @ReactMethod
    fun getAllProducts(promise: Promise) {
        productViewModel.loadAllProducts()
        productViewModel.productsState.observeForever { result ->
            when (result) {
                is Result.Success -> {
                    // 将List<Product>转换为RN可识别的WritableArray
                    val productsArray = Arguments.createArray()
                    result.data.forEach { product ->
                        val productMap = Arguments.createMap().apply {
                            putInt("id", product.id)
                            putString("title", product.title)
                            putDouble("price", product.price)
                            putString("description", product.description)
                            putString("category", product.category)
                            putString("image", product.image)
                        }
                        productsArray.pushMap(productMap)
                    }
                    promise.resolve(productsArray)
                    // 移除观察者避免内存泄漏
                    productViewModel.productsState.removeObserver { }
                }
                is Result.Failure -> {
                    promise.reject("FETCH_ERROR", result.exception.message)
                    productViewModel.productsState.removeObserver { }
                }
            }
        }
    }
}

5. 注册Native Module

创建Package类并在MainApplication中注册模块:

// Package类
class ProductPackage : ReactPackage {
    override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
        return listOf(ProductModule(reactContext))
    }

    override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
        return emptyList()
    }
}

// 在MainApplication的getPackages方法中添加
override fun getPackages(): List<ReactPackage> {
    val packages = PackageList(this).packages
    packages.add(ProductPackage())
    return packages
}

二、React Native端:调用原生模块并渲染UI

在RN组件中导入原生模块,调用方法获取数据后渲染列表:

import { NativeModules, FlatList, Text, View, ActivityIndicator, Alert } from 'react-native';
import { useState, useEffect } from 'react';

const { ProductModule } = NativeModules;

const ProductListScreen = () => {
  const [products, setProducts] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    fetchProducts();
  }, []);

  const fetchProducts = async () => {
    try {
      const result = await ProductModule.getAllProducts();
      setProducts(result);
    } catch (error) {
      Alert.alert('请求失败', error.message);
    } finally {
      setLoading(false);
    }
  };

  if (loading) {
    return <ActivityIndicator size="large" color="#0066cc" />;
  }

  return (
    <View style={{ flex: 1, padding: 16 }}>
      <FlatList
        data={products}
        keyExtractor={(item) => item.id.toString()}
        renderItem={({ item }) => (
          <View style={{ marginBottom: 16, padding: 12, borderWidth: 1, borderColor: '#eee', borderRadius: 8 }}>
            <Text style={{ fontSize: 18, fontWeight: '600' }}>{item.title}</Text>
            <Text style={{ fontSize: 16, color: '#ff6600', marginTop: 4 }}>${item.price.toFixed(2)}</Text>
            <Text style={{ marginTop: 8, color: '#666' }}>{item.description}</Text>
          </View>
        )}
      />
    </View>
  );
};

export default ProductListScreen;

三、关键注意事项

  • 内存泄漏防护:Native Module中LiveData的观察者在回调后必须移除,避免内存泄漏。
  • 数据类型兼容:Android端的实体类需转换为RN支持的WritableMap/WritableArray,确保字段类型匹配。
  • 错误处理:两端都要覆盖网络异常、API返回错误等场景,给出友好提示。
  • 依赖优化:实际项目建议用Hilt等依赖注入框架管理ViewModel、Repository实例,避免硬编码初始化。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 02:36:30