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

GSON解析方法:解决Activity不等待API完成及大JSON解析问题

解决PriceActivity不等待API请求完成+大型JSON解析问题

嘿,这个问题我太熟了!核心原因是网络请求是异步操作,你直接在Activity里调用API的方法,它会立刻往下走,根本不会等请求返回数据。我分两块给你讲解决方案,先搞定异步等待的问题,再处理大型JSON的解析:

一、让Activity正确等待API请求完成

这里有几种主流的实现方式,你可以根据自己的项目语言(Java/Kotlin)选:

1. 用Callback回调接口(Java/Kotlin通用)

先定义一个回调接口,让API类在请求完成后主动通知Activity:

// 定义回调接口
public interface CryptoPriceCallback {
    void onDataLoaded(List<CryptoPrice> prices);
    void onError(String errorMessage);
}

// API类里的请求方法
public class CryptoApi {
    public void fetchPrices(CryptoPriceCallback callback) {
        // 开启子线程执行网络请求(避免阻塞主线程)
        new Thread(() -> {
            try {
                // 执行网络请求,获取输入流(这里用OkHttp举例)
                Request request = new Request.Builder().url("你的加密货币API地址").build();
                Response response = new OkHttpClient().newCall(request).execute();
                InputStream inputStream = response.body().byteStream();
                
                // 解析数据(后面讲大型JSON的流式解析)
                List<CryptoPrice> prices = parseLargeJson(inputStream);
                
                // 切回主线程回调结果,保证UI操作安全
                new Handler(Looper.getMainLooper()).post(() -> callback.onDataLoaded(prices));
            } catch (Exception e) {
                new Handler(Looper.getMainLooper()).post(() -> callback.onError(e.getMessage()));
            }
        }).start();
    }
}

// PriceActivity里调用并实现回调
public class PriceActivity extends AppCompatActivity implements CryptoPriceCallback {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_price);
        
        CryptoApi api = new CryptoApi();
        api.fetchPrices(this); // 传入回调实现
    }

    @Override
    public void onDataLoaded(List<CryptoPrice> prices) {
        // 这里就拿到完整数据了,放心更新UI
        updatePriceList(prices);
    }

    @Override
    public void onError(String errorMessage) {
        // 处理请求失败的情况,比如弹提示
        Toast.makeText(this, "请求失败:" + errorMessage, Toast.LENGTH_SHORT).show();
    }
}

2. 用Kotlin协程(推荐Kotlin项目使用)

协程能让异步代码写得像同步一样简洁,还能自动处理线程切换:

// API类定义挂起函数
class CryptoApi {
    private val okHttpClient = OkHttpClient()

    suspend fun fetchPrices(): List<CryptoPrice> {
        val request = Request.Builder()
            .url("你的加密货币API地址")
            .build()
        
        // 切换到IO线程执行网络请求,避免阻塞主线程
        return withContext(Dispatchers.IO) {
            val response = okHttpClient.newCall(request).execute()
            val inputStream = response.body?.byteStream() ?: throw Exception("空响应")
            // 流式解析大型JSON
            parseLargeJson(inputStream)
        }
    }
}

// PriceActivity里调用
class PriceActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_price)
        
        val api = CryptoApi()
        // 用lifecycleScope绑定Activity生命周期,避免内存泄漏
        lifecycleScope.launch {
            try {
                val prices = api.fetchPrices()
                // 协程自动切回主线程,直接更新UI
                updatePriceList(prices)
            } catch (e: Exception) {
                Toast.makeText(this@PriceActivity, "请求失败:${e.message}", Toast.LENGTH_SHORT).show()
            }
        }
    }
}

二、正确解析大型JSON数据

如果JSON数据量很大,直接把整个字符串转成对象列表很容易触发OOM(内存溢出),这时候必须用流式解析,逐行读取JSON内容,而不是一次性加载到内存:

1. Gson流式解析示例(Java/Kotlin通用)

private List<CryptoPrice> parseLargeJson(InputStream inputStream) throws IOException {
    List<CryptoPrice> prices = new ArrayList<>();
    JsonReader reader = new JsonReader(new InputStreamReader(inputStream));
    
    reader.beginArray(); // 假设API返回的根节点是数组
    while (reader.hasNext()) {
        // 逐个解析单个JSON对象,只把当前对象加载到内存
        CryptoPrice price = new Gson().fromJson(reader, CryptoPrice.class);
        prices.add(price);
    }
    reader.endArray();
    reader.close();
    return prices;
}

2. 额外优化建议

  • 分页请求:如果API支持分页,尽量分多次请求小批量数据(比如每次请求50条),比一次拿几千条数据更高效,也更省内存。
  • 忽略无用字段:如果JSON里有很多你不需要的字段,在实体类里用@Expose(serialize = false, deserialize = false)(Gson)或者@Json(ignore = true)(Moshi)忽略它们,减少内存占用。
  • 用Moshi替代Gson:Moshi的流式解析性能更好,对Kotlin的空安全支持更友好,语法和Gson接近,学习成本很低。

最后再提醒一句:不管用哪种方式,网络请求绝对不能放在主线程,必须在子线程执行;更新UI的时候一定要切回主线程,不然会直接崩溃哦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 08:59:37