无API接口时如何用Retrofit获取网站纯字符串数据?异常解决
这问题我之前对接第三方纯文本接口时也踩过坑——你用的GsonConverterFactory默认会把所有响应当成合法JSON来解析,但你的接口返回的是不带引号的纯文本字符串(比如18.06#21.06#19.42),完全不符合JSON格式,所以才会抛出Use JsonReader.setLenient(true) to accept malformed JSON的错误。
下面给你两个最靠谱的解决办法,按需选择:
方法一:使用ScalarsConverterFactory(推荐)
Retrofit专门提供了ScalarsConverterFactory来处理字符串、基本数据类型这类非JSON响应,步骤如下:
1. 添加依赖
在你的app模块build.gradle(或build.gradle.kts)中添加Scalars转换器的依赖,版本要和你当前使用的Retrofit版本保持一致:
// 假设你的Retrofit版本是2.9.0,版本号请自行匹配 implementation 'com.squareup.retrofit2:converter-scalars:2.9.0'
2. 修改ApiClient配置
把ScalarsConverterFactory添加到Retrofit的转换器工厂列表中,替换原来的GsonConverterFactory(如果你的项目里只有这个纯字符串接口的话):
public class ApiClient { public static Retrofit retrofit; public static String BASE_URL = "https://prdec.com/status_app/"; public static Retrofit getRetrofit(){ if (retrofit == null){ retrofit = new Retrofit.Builder().baseUrl(BASE_URL) // 用Scalars转换器替代Gson,专门处理纯文本 .addConverterFactory(ScalarsConverterFactory.create()) .build(); } return retrofit; } }
如果你的项目同时需要处理JSON接口和纯字符串接口,就把ScalarsConverterFactory放在GsonConverterFactory前面(Retrofit会按顺序尝试转换器):
retrofit = new Retrofit.Builder().baseUrl(BASE_URL) .addConverterFactory(ScalarsConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create()) .build();
3. 验证代码
你的ApiService和MainActivity里的调用代码不需要修改,现在重新运行就能正常获取到纯字符串响应了。
方法二:自定义Gson的宽松解析模式(不推荐)
虽然可以通过设置Gson的宽松模式来绕过JSON格式检查,但这种方式属于“妥协式”解决,可能会引入潜在的解析问题,只建议临时测试时使用:
修改ApiClient中的Gson配置:
Gson gson = new GsonBuilder() .setLenient() // 开启宽松解析,允许非JSON格式的响应 .create(); retrofit = new Retrofit.Builder().baseUrl(BASE_URL) .addConverterFactory(GsonConverterFactory.create(gson)) .build();
额外:解析返回的字符串
拿到纯字符串后,你可以按#分割成具体的数值,比如在onResponse中处理:
@Override public void onResponse(Call<String> call, Response<String> response) { if (response.isSuccessful() && response.body() != null) { String rawData = response.body(); // 按#分割字符串 String[] valueArray = rawData.split("#"); // 遍历转成数值类型 for (String valueStr : valueArray) { try { float temperature = Float.parseFloat(valueStr); // 这里做你需要的业务处理,比如显示到UI上 Log.d(TAG, "解析到数值:" + temperature); } catch (NumberFormatException e) { Log.e(TAG, "数值解析失败:" + e.getMessage()); } } } else { Toast.makeText(MainActivity.this, "请求失败", Toast.LENGTH_SHORT).show(); } }
内容的提问来源于stack exchange,提问作者user13496256

