JSON数组首字母缺失及HTTP Get请求数组解析技术问询
问题1:JSON数组存在首字母缺失的情况该如何处理?
咱们先拆解这个问题,通常分两种常见场景,对应不同的解决办法:
场景1:JSON语法本身不合法(数组标记缺失)
如果是后端返回的JSON字符串本身有语法错误——比如本该是标准数组格式[{...}, {...}],但开头少了[,或者结尾少了],导致无法被解析器识别为数组。这种情况优先让后端修复数据源,但如果暂时没法改后端,咱们可以手动修正字符串:
String rawJson = "你收到的有问题的JSON"; // 补全开头的[ if (!rawJson.trim().startsWith("[")) { rawJson = "[" + rawJson; } // 补全结尾的] if (!rawJson.trim().endsWith("]")) { rawJson += "]"; } // 现在可以用这个修正后的字符串去解析了
场景2:字段键名首字母与实体类属性不匹配
另一种情况是JSON里的字段首字母是小写(比如category_id),但你的Java实体类属性用了驼峰式首字母大写(比如categoryId),导致解析时字段映射失败。这种情况用序列化注解就能搞定,比如Gson的@SerializedName:
public class Category { @SerializedName("category_id") // 对应JSON里的字段名 private String categoryId; // 你的实体类属性名 @SerializedName("category_name") private String categoryName; @SerializedName("parent_id") private int parentId; // 别忘了空构造方法、getter和setter }
这样解析器就能正确把JSON字段映射到实体类属性上了。
问题2:Android中解析HTTP GET请求返回的JSON数组
我基于你给的初始代码,一步步帮你补全实现,注意绝对不能在主线程发网络请求,所以咱们用基础的AsyncTask(新手友好),最后再给你推荐现代Android开发常用的Retrofit方案。
第一步:先配置基础权限和依赖
- 添加网络权限:在
AndroidManifest.xml里加一行:
<uses-permission android:name="android.permission.INTERNET" />
如果你的APP目标是Android 9+,还要处理明文HTTP的问题:要么接口用HTTPS,要么在res/xml下创建network_security_config.xml:
<?xml version="1.0" encoding="utf-8"?> <network-security-config> <base-config cleartextTrafficPermitted="true" /> </network-security-config>
然后在Manifest的application标签里引用:
<application ... android:networkSecurityConfig="@xml/network_security_config">
- 添加Gson依赖:在模块级
build.gradle的dependencies里加:
implementation 'com.google.code.gson:gson:2.10.1'
第二步:创建实体类匹配JSON结构
先写一个Category.java类,对应你收到的JSON字段:
public class Category { private String category_id; private String category_name; private int parent_id; // 空构造方法必须要有,Gson解析需要 public Category() {} // Getter和Setter方法 public String getCategory_id() { return category_id; } public void setCategory_id(String category_id) { this.category_id = category_id; } public String getCategory_name() { return category_name; } public void setCategory_name(String category_name) { this.category_name = category_name; } public int getParent_id() { return parent_id; } public void setParent_id(int parent_id) { this.parent_id = parent_id; } }
如果觉得下划线字段名看着别扭,就用问题1里的@SerializedName改成驼峰式就行。
第三步:补全Welcome Activity的代码
把你给的初始代码补全,加上网络请求和解析逻辑:
public class Welcome extends Activity { Button btnLogout; TextView tvWelcome; // 假设你有个TextView显示欢迎语,记得在布局里加 @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_home); // 初始化控件 btnLogout = findViewById(R.id.btn_logout); tvWelcome = findViewById(R.id.tv_welcome); // 显示欢迎语 String username = getIntent().getStringExtra("Username"); if (username != null) { tvWelcome.setText("Welcome, " + username); } // 发起网络请求获取并解析分类数组 new FetchCategoriesTask().execute(); // 退出按钮逻辑 btnLogout.setOnClickListener(v -> { Intent loginIntent = new Intent(Welcome.this, LoginActivity.class); startActivity(loginIntent); finish(); }); } // 用AsyncTask在后台处理网络请求,避免阻塞主线程 private class FetchCategoriesTask extends AsyncTask<Void, Void, List<Category>> { @Override protected List<Category> doInBackground(Void... voids) { List<Category> categoryList = new ArrayList<>(); // 替换成你的实际API地址 String apiUrl = "https://your-api-domain.com/get-categories"; try { URL url = new URL(apiUrl); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); connection.setConnectTimeout(5000); // 5秒超时 connection.setReadTimeout(5000); // 读取响应内容 BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); StringBuilder responseBuilder = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { responseBuilder.append(line); } reader.close(); connection.disconnect(); // 用Gson解析JSON数组 Gson gson = new Gson(); Category[] categories = gson.fromJson(responseBuilder.toString(), Category[].class); if (categories != null) { categoryList = Arrays.asList(categories); } } catch (IOException e) { e.printStackTrace(); // 实际开发中要处理异常,比如提示用户网络错误 } return categoryList; } @Override protected void onPostExecute(List<Category> categories) { super.onPostExecute(categories); // 这里回到主线程,处理解析后的数组,比如显示到RecyclerView或打印日志 if (categories != null && !categories.isEmpty()) { for (Category cat : categories) { Log.d("CategoryInfo", "ID: " + cat.getCategory_id() + " | Name: " + cat.getCategory_name()); } } else { Log.d("CategoryInfo", "未获取到分类数据"); } } } }
更推荐的现代方案:Retrofit + Coroutines
如果是新开发的项目,更推荐用Retrofit,代码更简洁且维护性更好:
- 添加依赖:在
build.gradle里加:
implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'
- 创建API接口:
public interface CategoryApi { @GET("get-categories") // 替换成你的接口路径 Call<List<Category>> getCategories(); }
- 在Activity里发起请求:
// 在onCreate方法里 // 初始化Retrofit Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://your-api-domain.com/") // 替换成你的API基础地址 .addConverterFactory(GsonConverterFactory.create()) .build(); CategoryApi categoryApi = retrofit.create(CategoryApi.class); // 用Coroutines在后台发起请求 CoroutineScope(Dispatchers.IO).launch { try { Response<List<Category>> response = categoryApi.getCategories().execute(); if (response.isSuccessful()) { List<Category> categories = response.body(); // 切回主线程更新UI runOnUiThread(() -> { if (categories != null) { // 处理数据,比如显示到列表 } }); } } catch (IOException e) { e.printStackTrace(); } }
内容的提问来源于stack exchange,提问作者techker
相关产品推荐
相关产品推荐

