Android——使用GSON库解析json数据(解析菜谱大全返回的JSON数据)

1.首先,在dependencies依赖库添加GSON库的依赖:

implementation 'com.google.code.gson:gson:2.8.6'
2.有关GSON

GSON提供了fromJson()和toJson()两个直接用于解析和生成JSON数据的方法,前者实现反序列化,后者实现了序列化,同时每个方法都提供了重载。

序列化:Serialization,将Java对象转换成JSON字符串。

反序列化:Deserialization,JSON字符串转换为Java对象。

3.举例:

①将以下JSON字符串转换为Java对象:

{"name":"张三","age":20}

那我们就可以定义一个Person类,并加入name和age这两个属性:

class Person{
public String name;
public int age;
Person(String name,int age){
this.name = name;
this.age = age;
}
}

然后调用如下代码:

Gson gson = new Gson();
String jsonData = "{\"name\":\"张三\",\"age\":20}";
Person person = gson.fromJson(jsonData,Person.class);

意思是:创建了一个GSON对象和一个JSON字符串,然后通过GSON对象的fromJson()方法,将这个字符串转换为Person类的对象,那么该Person对象就是一个名字叫张三,年龄20岁的人了。

②将Java对象转换为JSON字符串:

Gson gson = new Gson();
Person person = new Person("张三",20);
String jsonData = gson.toJson(person);
//这一步后会得到{"name":"张三","age":20}

③将JSON数组转换为Java对象:

这也是我们在开发中常用的,解析JSON数组需要用到TypeToken将期望解析成的数据类型传入到fromJson()方法中,如下:

List<RecipeBean> recipes = gson.fromJson(jsonData,new TypeToken<List<RecipeBean>>(){}.getType());

这里在TypeToken后的{}其实是:这里new生成的是一个匿名类的对象,该匿名类继承自TypeToken,{}代表匿名类的内部,只不过这个内部什么都没有写。

现在我们用这个方法解析以下菜谱大全接口(https://www.showapi.com/apiGateway/view/1164)返回的JSON字符串吧。

如下图:

 可以看到,我们真正需要的数据是红框内的,在datas这个JSON数组中,有绿框内的12个属性:des,smallImg......

上图是官网中的返回数据举例,其实我们真实返回的数据还有时间,如下图:

 

 

 所以一共是13个属性。

那么我们创建的JAVA类应当要有这十三个属性,如下代码:

package com.kotlin.activitystudy.pojo;

import java.io.Serializable;
import java.util.List;

public class RecipeBean implements Serializable {
    private String cpName;
    private String ct;
    private String des;
    private String id;
    private String largeImg;
    private String smallImg;
    private String tip;
    private String type;
    private String type_v1;
    private String type_v2;
    private String type_v3;
    private List<StepBean> steps;
    private List<YlBean> yl;

    public String getCpName() {
        return cpName;
    }

    public void setCpName(String cpName) {
        this.cpName = cpName;
    }

    public String getCt() {
        return ct;
    }

    public void setCt(String ct) {
        this.ct = ct;
    }

    public String getDes() {
        return des;
    }

    public void setDes(String des) {
        this.des = des;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getLargeImg() {
        return largeImg;
    }

    public void setLargeImg(String largeImg) {
        this.largeImg = largeImg;
    }

    public String getSmallImg() {
        return smallImg;
    }

    public void setSmallImg(String smallImg) {
        this.smallImg = smallImg;
    }

    public String getTip() {
        return tip;
    }

    public void setTip(String tip) {
        this.tip = tip;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getType_v1() {
        return type_v1;
    }

    public void setType_v1(String type_v1) {
        this.type_v1 = type_v1;
    }

    public String getType_v2() {
        return type_v2;
    }

    public void setType_v2(String type_v2) {
        this.type_v2 = type_v2;
    }

    public String getType_v3() {
        return type_v3;
    }

    public void setType_v3(String type_v3) {
        this.type_v3 = type_v3;
    }

    public List<StepBean> getSteps() {
        return steps;
    }

    public void setSteps(List<StepBean> steps) {
        this.steps = steps;
    }

    public List<YlBean> getYl() {
        return yl;
    }

    public void setYl(List<YlBean> yl) {
        this.yl = yl;
    }


}

应该有注意到以下两个属性:

private List<StepBean> steps;

private List<YlBean> yl;

观察返回的数据steps部分:

 

 

 steps中的内容并不是JSON字符串,而是JSON数组,并且该数组中有content,imgUrl,orderNum三个字段。

所以,我们需要新建一个对应属性的Java类,如下:

package com.kotlin.activitystudy.pojo;

import java.io.Serializable;

public class StepBean implements Serializable {
    private String content;
    private String imgUrl;
    private int oderNum;
    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public String getImgUrl() {
        return imgUrl;
    }

    public void setImgUrl(String imgUrl) {
        this.imgUrl = imgUrl;
    }

    public int getOderNum() {
        return oderNum;
    }

    public void setOderNum(int oderNum) {
        this.oderNum = oderNum;
    }

}

private List<StepBean> steps;的意思是steps是一个StepBean类型的泛型集合。有关泛型可参考之前的笔记:https://www.cnblogs.com/Xiang-MY/p/16060687.html

private List<YlBean> yl;同理,贴一下对应JAVA类的代码:

package com.java.cookbook.pojo;

import java.io.Serializable;

public class YlBean implements Serializable {
    private String ylName;
    private String ylUnit;
    public String getYlName() {
        return ylName;
    }

    public void setYlName(String ylName) {
        this.ylName = ylName;
    }

    public String getYlUnit() {
        return ylUnit;
    }

    public void setYlUnit(String ylUnit) {
        this.ylUnit = ylUnit;
    }
}

 到目前为止,算是做好了准备工作,接下来就是用Gson去解析,解析的代码也很少,如下:

List<RecipeBean> recipes = new Gson().fromJson(new JSONObject(jsonStr).getJSONObject("showapi_res_body").getJSONArray("datas").toString(),new TypeToken<List<RecipeBean>>(){}.getType());

可以看到,我们用了getJSONObject()和getJSONArray()这两个方法。这是系统自带的JSONObject方式解析JSON数据中的两个方法,如下:

 

 

 绿框的JSONObject类中包含了很多个方法,相关函数介绍如下:

JSONObject getJSONObject(String key):如果JSONObject对象中的value是一个JSONObject对象,即根据key获取对应的JSONObject对象。

JSONObject getJSONArray(String key):如果JSONObject对象中的value是一个JSONObject数组,即根据key获取对应的JSONObject数组。Object get(String key):根据key值获取JSONObject中对应的value值,获取到的为Object类型,需要手动转换为需要的类型。

 对应以上的内容,再看看返回的JSON数据:

 

 

 可以看到,showapi_res_body需要用getJSONObject方法,而datas需要使用getJSONArray方法。

经历new JSONObject(jsonStr).getJSONObject("showapi_res_body").getJSONArray("datas").toString()后,我们就拿到了datas下的JSON数据,对应的JAVA在上面已经创建好了。

经过fromJson()方法后,我们就拿到了解析的数据,现在我们可以通过对象.属性的方式使用这些想要的数据了。

【备注:还有另一种方法,即不使用JSONObject,那么我们就需要创建Java类的时候要将返回的所有数据对应的属性考虑进去。(此处的java类只是考虑了datas下的属性)

即:需要创建ResponseClass类,该类下应该包含属性如下:

 

 然后需要为"showapi_res_body"属性创建对应的泛型集合的java类BodyClass,该类的属性应该有:

 

 然后,再为其datas属性创建对应泛型集合的java类。

总之就是一层层弄下去,可是显而易见,除了datas中的数据我们并不需要其余的,所以此处用了JSONObject方式只拿了datas对应的JSONObject数组。】

 

实战:

例如:我现在想要拿到蛋类菜谱集合中,序列号为2的菜品名称,并显示到屏幕上。

接在之前的OKHttp异步GET请求数据后:https://www.cnblogs.com/Xiang-MY/p/16694714.html

修改之前的NetUtil工具类,在数据请求成功的回调中加上对数据的解析,并将解析后的集合传回去。代码如下:

package com.kotlin.activitystudy.http;

import android.util.Log;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.kotlin.activitystudy.pojo.RecipeBean;

import org.json.JSONObject;

import java.io.IOException;
import java.util.List;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

public class NetUtil {
    public interface OnRecipeQueriedCallback{
        void onSuccess(List<RecipeBean> recipes);
        void onFailure(Exception e);
    }

    public static void queryRecipe(String tag,final OnRecipeQueriedCallback callback){
        OkHttpClient okHttpClient = new OkHttpClient();
        Request request = new Request.Builder()
                .url(String.format("http://route.showapi.com/1164-1?showapi_appid=填自己的&type= %s&showapi_sign=填自己的",tag))
                .build();
        Call call = okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                e.printStackTrace();
                callback.onFailure(e);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                try {

                    String jsonStr = response.body().string();
                    List<RecipeBean> recipes = new Gson().fromJson(new JSONObject(jsonStr).getJSONObject("showapi_res_body").getJSONArray("datas").toString(),new TypeToken<List<RecipeBean>>(){}.getType());
                    callback.onSuccess(recipes);
                }catch (Exception e){
                    callback.onFailure(e);
                }
            }
        });
    }
}

修改Activity的代码:

package com.kotlin.activitystudy.http;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import com.kotlin.activitystudy.R;
import com.kotlin.activitystudy.pojo.RecipeBean;

import java.util.List;

public class OKHttpActivity2 extends AppCompatActivity {

    private Button btn_Request;
    private TextView responseText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_okhttp);
        btn_Request = findViewById(R.id.btn_sendRequest);
        responseText = findViewById(R.id.responseText);
        btn_Request.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                sendRequestWithHttpURLConnection();
            }
        });
    }

    private void sendRequestWithHttpURLConnection() {
        NetUtil.queryRecipe("蛋类", new NetUtil.OnRecipeQueriedCallback() {
            @Override
            public void onSuccess(List<RecipeBean> recipes) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        responseText.setText(recipes.get(2).getCpName());
                    }
                });
            }

            @Override
            public void onFailure(Exception e) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Log.d("OKHttpActivity2","网络错误");
                    }
                });
            }
        });
    }


}

运行如下:

 

 成功拿到了它的数据。

posted @ 2022-09-19 00:51  虞美人体重90  阅读(2526)  评论(0编辑  收藏  举报