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类型的泛型集合。
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的菜品名称,并显示到屏幕上。
修改之前的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","网络错误");
}
});
}
});
}
}
运行如下:
成功拿到了它的数据。