Retrofit解析无URL响应求助:JSON数组解析及TextView赋值问题
解决Retrofit无法获取JSON数组响应的问题
我完全懂你现在的困扰——明明搭好了Retrofit的整套结构,却拿不到半点响应,这种情况我也碰到过好几次!咱们从最容易踩坑的地方开始排查,一步步解决:
1. 先检查Retrofit客户端的核心配置
这是最容易出错的基础环节:
- 必须添加JSON解析转换器:Retrofit本身不会自动解析JSON,一定要加上
GsonConverterFactory(如果用Gson的话),不然接口返回的响应根本没法转成你的DistrictDTO对象。正确配置示例:public class RetrofitClient { private static final String BASE_URL = "https://your-api-base-url.com/"; // 注意末尾的/必须加 private static Retrofit retrofit; public static Retrofit getClient() { if (retrofit == null) { retrofit = new Retrofit.Builder() .baseUrl(BASE_URL) .addConverterFactory(GsonConverterFactory.create()) // 关键!不能少 .build(); } return retrofit; } } - BaseUrl必须以
/结尾:如果你的baseUrl是https://xxx.com/api,而接口路径是districts,Retrofit会拼接成https://xxx.comdistricts,直接导致请求地址错误,这坑我踩过不止一次!
2. 确认Api Service的接口定义是否正确
因为你要解析的是对象数组,接口的返回类型必须对应:
- 接口方法的返回值应该是
Call<List<DistrictDTO>>,而不是单个的Call<DistrictDTO>!示例:public interface ApiService { @GET("districts") // 这里的路径要和后端接口完全匹配 Call<List<DistrictDTO>> getDistricts(); } - 核对HTTP方法(@GET/@POST等)和路径是否和后端一致,比如后端是POST接口,你用@GET肯定拿不到数据。
3. 检查DistrictDTO类的映射正确性
Gson解析的核心是字段匹配,这里最容易出细节问题:
- 字段名必须和JSON键一致,或者用
@SerializedName映射:比如JSON里的键是district_id,你的DTO字段是districtId,那必须加注解:public class DistrictDTO { @SerializedName("district_id") private int districtId; @SerializedName("district_name") private String districtName; // 必须要有无参构造函数!Gson需要它来实例化对象 public DistrictDTO() {} // Getter和Setter方法 public int getDistrictId() { return districtId; } public void setDistrictId(int districtId) { this.districtId = districtId; } public String getDistrictName() { return districtName; } public void setDistrictName(String districtName) { this.districtName = districtName; } } - 确保字段类型和JSON里的类型完全匹配:比如JSON里是数字类型的ID,DTO里不能用String,否则解析会失败。
- 一定要保留无参构造函数,不然Gson没法创建对象。
4. Activity中的调用逻辑排查
异步请求和UI更新的细节很容易忽略:
- 必须处理
onFailure回调:很多时候问题出在这里,比如网络超时、域名解析失败,一定要打印错误信息:ApiService apiService = RetrofitClient.getClient().create(ApiService.class); Call<List<DistrictDTO>> call = apiService.getDistricts(); call.enqueue(new Callback<List<DistrictDTO>>() { @Override public void onResponse(Call<List<DistrictDTO>> call, Response<List<DistrictDTO>> response) { if (response.isSuccessful() && response.body() != null) { // 这里处理成功的响应,注意更新UI要在主线程 runOnUiThread(() -> { // 把数据设置到TextView,比如拼接所有 districtName StringBuilder sb = new StringBuilder(); for (DistrictDTO district : response.body()) { sb.append(district.getDistrictName()).append("\n"); } yourTextView.setText(sb.toString()); }); } else { // 响应成功但没有数据,打印响应码看看 Log.e("Retrofit", "Response failed: " + response.code()); } } @Override public void onFailure(Call<List<DistrictDTO>> call, Throwable t) { // 这里打印错误信息,能直接定位问题! Log.e("RetrofitError", "Request failed: " + t.getMessage(), t); } }); - 更新UI必须在主线程:Retrofit的
onResponse和onFailure是在子线程执行的,直接更新TextView会崩溃,一定要用runOnUiThread或者借助ViewModel/LiveData。 - 别忘了加网络权限:在
AndroidManifest.xml里添加<uses-permission android:name="android.permission.INTERNET" />,没有这个权限的话,连网络请求都发不出去!
5. 调试小技巧:先看原始响应
如果还是找不到问题,先跳过解析,直接获取原始的响应字符串,确认是不是真的拿到了JSON:
// 临时修改ApiService的方法 @GET("districts") Call<ResponseBody> getRawDistricts(); // 调用时打印原始内容 Call<ResponseBody> rawCall = apiService.getRawDistricts(); rawCall.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { if (response.isSuccessful()) { try { String rawJson = response.body().string(); Log.d("RawJSON", rawJson); // 看看返回的是不是预期的数组结构 } catch (IOException e) { e.printStackTrace(); } } } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { Log.e("RawError", t.getMessage(), t); } });
这样能快速确认是网络请求的问题,还是JSON解析的问题。
按照上面的步骤一步步排查,大概率能找到问题所在!
内容的提问来源于stack exchange,提问作者Nabin Dhakal
相关产品推荐
相关产品推荐

