【问题标题】:Parsing JSON W/ API Key使用 API 密钥解析 JSON
【发布时间】:2013-04-29 19:36:42
【问题描述】:

我是 JSON 和解析数据等方面的新手。我使用 GSON 并尝试提取 JSONArray“系统”,然后显示 JSONObject 的“系统名称”,然后显示它。 下面是要提取的 JSON 数据的示例。

 {
"systems": [
  {
  "city": "Petaluma",
  "country": "US",
  "postal_code": "94954",
  "state": "CA",
  "status": "normal",
  "system_id": 66,
  "system_name": "Smith Residence",
  "system_public_name": "Residential System",
  "timezone": "America/Los_Angeles"
},
{
  "city": "Atherton",
  "country": "US",
  "postal_code": "94954",
  "state": "CA",
  "status": "error",
  "system_id": 77,
  "system_name": "Jones Residence",
  "system_public_name": "Jones Residence",
  "timezone": "America/Los_Angeles"
}
 ]
}

API 使用 API_KEY 进行身份验证,这样使用

https://api.company.com/api/systems?key=123ABC

代码

public class PullJSONData extends Activity {

TextView systemsTextView;
ProgressDialog progressDialog;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    systemsTextView = (TextView) findViewById(R.id.textView);

    this.retrieveSystems();
}
void retrieveSystems() {
    progressDialog = ProgressDialog.show(this, "Please wait...",
            "Retrieving data...", true, true);
    SystemsRetrieverAsyncTask task = new SystemsRetrieverAsyncTask();
    task.execute();
    progressDialog.setOnCancelListener(new CancelListener(task));
}

private class SystemsRetrieverAsyncTask extends AsyncTask<Void, Void, Void> {
    Response response;
    @Override
    protected Void doInBackground(Void... params) {
        String url = "https://api.company.com/api";
        HttpGet getRequest = new HttpGet(url);

        try {
            DefaultHttpClient httpClient = new DefaultHttpClient();
            HttpResponse getResponse = httpClient.execute(getRequest);
            final int statusCode = getResponse.getStatusLine()
                    .getStatusCode();

            if (statusCode != HttpStatus.SC_OK) {
                Log.w(getClass().getSimpleName(), "Error " + statusCode
                        + " for URL " + url);
                return null;
            }

            HttpEntity getResponseEntity = getResponse.getEntity();
            InputStream httpResponseStream = getResponseEntity.getContent();
            Reader inputStreamReader = new InputStreamReader(
                    httpResponseStream);

            Gson gson = new Gson();
            SystemList systemList = gson.fromJson(jsonString, SystemList.class);

            for (int i = 0; i < systemList.systems.size(); i++)
            {
               System s = systemList.systems.get(i);
            }
            this.response = gson
                    .fromJson(inputStreamReader, Response.class);
        } catch (IOException e) {
            getRequest.abort();
            Log.w(getClass().getSimpleName(), "Error for URL " + url, e);
        }

        return null;
    }

    @Override
    protected void onPostExecute(Void result) {
        super.onPostExecute(result);

        StringBuilder builder = new StringBuilder();
        for (System systems : this.response.data) {

            builder.append(String.format(
                    "<br>System: <b>%s</b><br>City: <b>%s</b><br><br>",
                    systems.getCountry(), systems.getCity()));

        }

        systemsTextView.setText(Html.fromHtml(builder.toString()));
        progressDialog.cancel();
    }

}

private class CancelListener implements OnCancelListener {

    AsyncTask<?, ?, ?> cancellableTask;

    public CancelListener(AsyncTask<?, ?, ?> task) {
        cancellableTask = task;
    }

    @Override
    public void onCancel(DialogInterface dialog) {
        cancellableTask.cancel(true);
    }

}

响应

public class Response {

ArrayList<System> data;

public Response() {
    data = new ArrayList<System>();
}

系统

public class System {

String city;
String country;

public System() {

    this.city = "";
    this.country = "";
}

public String getCity() {
    return this.city;
}

public String getCountry() {
    return this.country;
}

系统列表

public class SystemList {
public List<System> systems;

public SystemList() { systems = new ArrayList<System>(); }
}

如果您需要查看完整源代码,请查找HERE

当前问题

  • NullPointerException
  • 来自 URL https://api.company.com/api/systems/ 的错误 401

    04-29 15:43:25.735:E/AndroidRuntime(3678):致命异常:主要 04-29 15:43:25.735: E/AndroidRuntime(3678): java.lang.NullPointerException 04-29 15:43:25.735: E/AndroidRuntime(3678): 在 com.jaisonbrooks.enlightenme.PullJSONData$SystemsRetrieverAsyncTask.onPostExecute(PullJSONData.java:96) 04-29 15:43:25.735: E/AndroidRuntime(3678): 在 com.jaisonbrooks.enlightenme.PullJSONData$SystemsRetrieverAsyncTask.onPostExecute(PullJSONData.java:1) 04-29 15:43:25.735: E/AndroidRuntime(3678): 在 android.os.AsyncTask.finish(AsyncTask.java:631) 04-29 15:43:25.735: E/AndroidRuntime(3678): 在 android.os.AsyncTask.access$600(AsyncTask.java:177) 04-29 15:43:25.735: E/AndroidRuntime(3678): 在 android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:644) 04-29 15:43:25.735: E/AndroidRuntime(3678): 在 android.os.Handler.dispatchMessage(Handler.java:99) 04-29 15:43:25.735: E/AndroidRuntime(3678): 在 android.os.Looper.loop(Looper.java:137) 04-29 15:43:25.735: E/AndroidRuntime(3678): 在 android.app.ActivityThread.main(ActivityThread.java:4898) 04-29 15:43:25.735: E/AndroidRuntime(3678): 在 java.lang.reflect.Method.invokeNative(Native Method) 04-29 15:43:25.735: E/AndroidRuntime(3678): 在 java.lang.reflect.Method.invoke(Method.java:511) 04-29 15:43:25.735: E/AndroidRuntime(3678): 在 com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1006) 04-29 15:43:25.735: E/AndroidRuntime(3678): 在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:773) 04-29 15:43:25.735: E/AndroidRuntime(3678): at dalvik.system.NativeStart.main(Native Method)

【问题讨论】:

    标签: java android json api parsing


    【解决方案1】:

    另一个选项(类似于上面的 jackson)是使用 Gson 库。在 json 处理方面做得很好。它也有很好的记录和理解。

    编辑:

    好的,所以在查看您的代码之后,您似乎过于复杂了 System 和 SystemList 类。

    public class System {
        public String city;
        public String country;
        public String postal_code;
        public String state;
        public String status;
        public String system_id;
        public String system_name;
        public String system_public_name;
        public String timezone;
    }
    
    public class SystemsList {
        public List<System> systems;
    }
    

    您需要做的就是确保 json 中的名称映射到数据模型中的名称。

    我还包含了一个完全通用的 GsonSerializer,以便可以将它重用于其他 gson 响应

    public class GsonSerializer 
    {
    private static final String TAG = "GsonSerializer";
    
    public static <T> Object seralizeData (String response, T t)
    {
        Gson serializer = new Gson();
    
        try 
        {
            return serializer.fromJson(response, t.getClass());
        } 
        catch (Exception e) 
        {
            e.printStackTrace();
            Logger.e(TAG, "deserialization failure: ".concat(response));
        }
    
        return null;
    }
    
    }
    

    您使用此类的方式如下。

     // Where mData is a class of type T
     mData = (T) GsonSerializer.seralizeData(Json, mData); 
     // or in a specific example
     mSystemList = (SystemList) GsonSerializer.seralizeData(Json, new SystemList());
    

    这应该足以让您可以即插即用。可能需要进行一些小的调整。

    【讨论】:

    • 我已经使用 GSON 库更新了我的代码,你能再看看它吗?
    【解决方案2】:

    【讨论】:

      【解决方案3】:

      您得到的响应是一个JSONObject{...},里面有一个JOSNArray[...],名为“systems”。

      如果您想解析JSONArray 中的元素(更多JSONObjects),您可以使用随Android 一起分发的org.json 包提供的类或使用另一个JSON 库,如@ 987654324@或Jackson

      首先您必须从最外层的JSONObject 中提取数据。为此,请致电myJSONObject.getJSONArray("systems");。结果值将是JSONArray 类型。您可以迭代它的 length() 在每个位置调用 getJSONObject(i)

      这些JSONObjects 包含您实际想要在本地使用的数据。

      最好创建一个模型类,其中包含JSONObject 的元素作为成员变量,并提供一个构造函数,该构造函数采用包含对象数据值的JSONObject

      然后,您可以在此构造函数中读取 JSONObject 的值,如下所示:this.city = myJSONObject.getString("city");

      对于初学者,您可以使用 org.json 包并熟悉 JSON 本身。

      【讨论】:

      • 我用一些示例代码更新了我的问题。你能再看看吗?
      【解决方案4】:

      我会推荐一个 JSON 序列化库。谷歌自己的GSON 是我找到的最好的。对于您的数据,您可以执行以下操作:

      创建一个与系统匹配的模型(我使用 getter 和 setter,有些只使用公共字段,每个人都有自己的):

      public class System
      {
         private String city;
      
         public String getCity { return city; }
         public void setCity(string c) { city = c; }
      
         private String country;
      
         public String getCountry{ return country; }
         public void setCountry(string c) { country = c; }
      
         // .. the rest of the fields here
      }
      
      public class SystemList
      {
          public List<System> systems;
      
          public SystemList() { systems = new List<System>(); }
      }
      

      然后要序列化您的顶级对象,请执行以下操作(注意,您的 JSON 包含在花括号 {} 中,这意味着顶级未命名对象。我们将使用 SystemList 表示)

      Gson gson = new Gson();
      SystemList systemList = gson.fromJson(jsonString, SystemList.class);
      
      for (int i = 0; i < systemList.systems.size(); i++)
      {
         System s = systemList.systems.get(i);
         // do something with system
      }
      

      【讨论】:

      • 根据您的建议添加了一些新代码,但是我得到了 NullPointerException - 看起来也是错误 401,
      • 401 将来自服务端,而不是客户端。我用你的 JSON 测试了我的代码,它工作了
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-01
      • 2017-03-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多