Android解析JSON为Java对象数组报No value for name错误
问题背景
Android开发过程中需要采集接口返回的JSON数据,解析为Java对象后存入对象数组,后续用于ListView和Fragment的数据展示。代码可正常启动运行,但日志输出JSON解析报错,此前尝试直接用JSONArray解析也未成功。
原有实现代码
import androidx.appcompat.app.AppCompatActivity; import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.ProtocolException; import java.net.URL; import java.util.ArrayList; public class MainActivity extends AppCompatActivity { ArrayList<Character> characterArray = new ArrayList<Character>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); CharacterGetData characterGetData = new CharacterGetData(); characterGetData.execute("https://swapi.dev/api/people/?format=json"); } //Character Class class Character{ String name; String height; String mass; } class CharacterGetData extends AsyncTask<String, String, String> { String name; String height; String mass; @Override protected String doInBackground(String... args) { try { URL obj = new URL(args[0]); HttpURLConnection connection = (HttpURLConnection) obj.openConnection(); connection.setRequestMethod("GET"); BufferedReader in = new BufferedReader( new InputStreamReader(connection.getInputStream())); String line; StringBuffer response = new StringBuffer(); while ((line = in.readLine()) != null) { response.append(line); } in.close(); JSONObject jsonObj = new JSONObject(response.toString()); Character character1 = new Character(); character1.name = jsonObj.getString("name"); character1.height = jsonObj.getString("height"); character1.mass = jsonObj.getString("mass"); characterArray.add(character1); Log.i("MainActivity", "The name is " + character1.name + "the height is " + character1.height); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException | JSONException e) { e.printStackTrace(); } return null; } }}
运行报错日志
W/System.err: org.json.JSONException: No value for name W/System.err: at org.json.JSONObject.get(JSONObject.java:400) W/System.err: at org.json.JSONObject.getString(JSONObject.java:561) W/System.err: at com.example.androidlabs.MainActivity$CharacterGetData.doInBackground(MainActivity.java:71) W/System.err: at com.example.androidlabs.MainActivity$CharacterGetData.doInBackground(MainActivity.java:43) W/System.err: at android.os.AsyncTask$3.call(AsyncTask.java:394) W/System.err: at java.util.concurrent.FutureTask.run(FutureTask.java:266) W/System.err: at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:305) W/System.err: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) W/System.err: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) W/System.err: at java.lang.Thread.run(Thread.java:923)
接口返回结构
调用接口地址:https://swapi.dev/api/people/?format=json
返回JSON结构如下:
{"count":82,"next":"https://swapi.dev/api/people/?page=2&format=json","previous":null,"results":[{"name":"Luke Skywalker","height":"172","mass":"77","hair_color":"blond","skin_color":"fair","eye_color":"blue","birth_year":"19BBY","gender":"male","homeworld":"https://swapi.dev/api/planets/1/","films":["https://swapi.dev/api/films/1/","https://swapi.dev/api/films/2/","https://swapi.dev/api/films/3/","https://swapi.dev/api/films/6/"],"species":[],"vehicles":["https://swapi.dev/api/vehicles/14/","https://swapi.dev/api/vehicles/30/"],"starships":["https://swapi.dev/api/starships/12/","https://swapi.dev/api/starships/22/"],"created":"2014-12-09T13:50:51.644000Z","edited":"2014-12-20T21:17:56.891000Z","url":"https://swapi.dev/api/people/1/"}]}
报错原因
解析逻辑层级错误:接口返回的最外层JSON对象仅包含count、next、previous、results四个字段,name/height/mass等人物属性字段都存在于results对应的JSON数组的子元素中,直接在最外层对象调用getString("name")自然会触发「No value for name」异常。
修复方案
- 调整JSON解析层级,先从最外层对象取出
results对应的JSON数组 - 遍历该数组,逐个取出每个人物对应的JSON子对象
- 从子对象中解析目标字段,封装为
Character实例存入列表
核心修复后的解析代码如下:
JSONObject jsonObj = new JSONObject(response.toString()); // 取出外层包裹的人物列表数组 JSONArray resultArr = jsonObj.getJSONArray("results"); // 遍历数组解析所有人物数据 for (int i = 0; i < resultArr.length(); i++) { JSONObject characterItem = resultArr.getJSONObject(i); Character character = new Character(); character.name = characterItem.getString("name"); character.height = characterItem.getString("height"); character.mass = characterItem.getString("mass"); characterArray.add(character); Log.i("MainActivity", "The name is " + character.name + " the height is " + character.height); }
额外优化建议
- 解析字段时优先使用
optString()替代getString(),字段不存在时会默认返回空字符串,避免直接抛出异常崩溃,提升代码健壮性 - 记得在
AndroidManifest.xml中添加<uses-permission android:name="android.permission.INTERNET" />权限,否则高版本Android系统会拦截网络请求 AsyncTask已在Android 11版本被官方废弃,后续可改用Retrofit/OkHttp等网络框架配合协程、线程池实现网络请求,减少版本兼容问题
内容的提问来源于stack exchange,提问作者newbie-coder
相关产品推荐
相关产品推荐

