【问题标题】:JSON Parsing in Android using Retrofit with JsonSyntaxException使用带有 JsonSyntaxException 的 Retrofit 在 Android 中解析 JSON
【发布时间】:2019-09-18 15:01:20
【问题描述】:

我在这个“解析世界”中真的很新,我知道已经有很多关于这个问题的讨论(所以如果它可能是一个重复的问题,我很抱歉),但是,即使遵循一些指南并阅读一些回答,我找不到解决问题的方法。

我的错误是

Expected BEGIN_OBJECT but was STRING at line 1 column 1

我需要解析的 JSON 如下:

[ 
   { 
      "id":1,
      "name":"first",
      "filename":"36ba664b-769c-404f-87e2-4ee8b9ac20a2.png",
      "floor":3,
      "north":48.31202,
      "south":48.310677,
      "east":10.1578865,
      "west":10.155078,
      "opacity":1.0,
      "level":0
   },
   { 
      "id":2,
      "name":"second",
      "filename":"522f79d4-0dd4-4425-9f81-70a73bdfebc6.png",
      "floor":0,
      "north":48.31202,
      "south":48.310677,
      "east":10.1578865,
      "west":10.155078,
      "opacity":1.0,
      "level":0
   },
   { 
      "id":3,
      "name":"third",
      "filename":"00e10310-739a-407e-86b0-373ba71144e1.png",
      "floor":0,
      "north":53.02099,
      "south":53.02067,
      "east":-1.4836869,
      "west":-1.4843831,
      "opacity":1.0,
      "level":0
     }
]

所以,按照本指南:http://www.androiddeft.com/retrofit-android/ 我创建了两个类:

数据和数据列表:

public class Data{

    @SerializedName("id")
    @Expose
    private Integer id;
    @SerializedName("name")
    @Expose
    private String name;
    @SerializedName("filename")
    @Expose
    private String filename;
    @SerializedName("floor")
    @Expose
    private Integer floor;
    @SerializedName("north")
    @Expose
    private Double north;
    @SerializedName("south")
    @Expose
    private Double south;
    @SerializedName("east")
    @Expose
    private Double east;
    @SerializedName("west")
    @Expose
    private Double west;
    @SerializedName("opacity")
    @Expose
    private Double opacity;
    @SerializedName("level")
    @Expose
    private Integer level;  
}

public class DataList{

    private ArrayList<Data> data = null;

    public ArrayList<Data> getData() {
        return data;
    }
}

在我创建 API 服务和改造客户端之后:

public interface DataApiService {

    @GET("/")
    Call<DataList> getMyJSON();
}

public class DataRequestManager {

    private static String baseUrl = "mylink";

    private static Retrofit getRetrofitInstance() {

        Gson gson = new GsonBuilder()
                .setLenient()
                //.enableComplexMapKeySerialization()
                .create();

        HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
        // set your desired log level
        if (BuildConfig.DEBUG) {
            logging.setLevel(HttpLoggingInterceptor.Level.BODY);
        } else {
            logging.setLevel(HttpLoggingInterceptor.Level.BASIC);
        }

        OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
        httpClient.connectTimeout(10, TimeUnit.SECONDS);
        httpClient.readTimeout(20, TimeUnit.SECONDS);
        httpClient.writeTimeout(20, TimeUnit.SECONDS);
        httpClient.addInterceptor(logging);
        OkHttpClient debuggclient = httpClient.build();

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(baseUrl)
                .addConverterFactory(new NullOnEmptyConverterFactory())
                .addConverterFactory(GsonConverterFactory.create(gson))
                .client(debuggclient).build();


        return retrofit;
    }

    public static DataApiService getApiService() {
        return getRetrofitInstance().create(DataApiService.class);
    }
}

但是当我这样做时:

        private static List<Data> dataList;

        DataApiService api = DataRequestManager.getApiService();

        Call<DataList> call = api.getMyJSON();

        call.enqueue(new Callback<DatasList>() {
            @Override
            public void onResponse(Call<DatasList> call, Response<DatasList> response) {

                if (response.isSuccessful()) {
                    //Got Successfully
                    dataList = response.body().getData();
                }
            }

            @Override
            public void onFailure(Call<DataList> call, Throwable t) {
                Toast.makeText(context, "Parsing Data Failed"+t.getMessage(),
                        Toast.LENGTH_LONG).show();
            }
        });

应用程序给了我 JsonSyntaxEception:

com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: 应为 BEGIN_OBJECT,但在第 1 行第 1 列路径 $

【问题讨论】:

  • 你确定你上面提到的json响应不包含任何字符串吗?

标签: android gson retrofit jsonparser


【解决方案1】:

您尝试做的是不正确的,因为您的响应只是一个数组。 DataList 可以接受的 json 应该是:

data : [
   { 
      "id":1,
      "name":"first",
      "filename":"36ba664b-769c-404f-87e2-4ee8b9ac20a2.png",
      "floor":3,
      "north":48.31202,
      "south":48.310677,
      "east":10.1578865,
      "west":10.155078,
      "opacity":1.0,
      "level":0
   },...
]

发生这种情况是因为在序列化时它将DataList 视为嵌套对象,因为为了访问数组,您需要执行dataList.data

解决您的问题的方法是将DataList 类替换为List&lt;Data&gt;

Call<List<Data>> call = api.getMyJSON();

【讨论】:

    【解决方案2】:

    你犯了一个非常基本的错误,你必须根据你的 json 更新你的界面:

    public interface DataApiService {
    
        @GET("/")
        Call<List<Data>> getMyJSON();
    }
    

    您期待响应并像这样解析它:

    {
      "data": [
        { .. }
      ]
    }
    

    但实际反应是这样的:

     [
        { .. }
     ]
    

    更新:

    在您的错误Expected BEGIN_ARRAY but was STRING at line 1 column 1 中,显然意味着您收到如下响应:

    "[
    
      {
        ...
      }
    
     ]"
    

    而不是这个:

     [
    
          {
            ...
          }
    
    ]
    

    我已将您的 Json 粘贴到编辑器中:

    正如您在左下角看到的 Ln: 1 Col: 1 和看到 Json 开头的光标,这里是 [,您会收到错误,因为您期望像 [{...}] 这样的数组,但实际响应是"[{...}]"

    只是为了证明我的观点,像这样更新你的界面:

    public interface DataApiService {
    
        @GET("/")
        Call<String> getMyJSON();
    }
    

    你不会得到错误。

    更多信息可以找到here

    【讨论】:

    • 我按照你的建议更改了我的界面:public interface DataApiService { @GET("/") Call&lt;List&lt;Data&gt;&gt; getMyJSON(); } 但现在我有例外:java.lang.IllegalStateException: Expected BEGIN_ARRAY but was STRING
    • @TheOldBlackbeard 你能分享你的json吗?
    • 当然我也改了private static List&lt;Data&gt; dataList; DataApiService api = DataRequestManager.getApiService(); Call&lt;List&lt;Data&gt;&gt; call = api.getMyJSON(); call.enqueue(new Callback&lt;List&lt;Data&gt;&gt;() { @Override public void onResponse(Call&lt;List&lt;Data&gt;&gt;call, Response&lt;List&lt;Data&gt;&gt;response) ecc。抄送。
    • 我在问题中写了 JSON
    • @TheOldBlackbeard 你得到这样的 Json “[ {...} ]”
    【解决方案3】:

    我找到了解决方案!由于主要问题是身份验证,我将我的 Retrofit Client 代码更改如下:

    public class DataRequestManager {
    
        private static String baseUrl = "mylink";
    
        //Get Retrofit Instance
        private static Retrofit getRetrofitInstance(Context context) {
    
            OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
    
            //Basic Auth
            String username="myUsername";
            String password="myPassword";
            String authToken = null;
    
            if (!TextUtils.isEmpty(username)
                    && !TextUtils.isEmpty(password)) {
                authToken = Credentials.basic(username, password);
            }
    
            //Create a new Interceptor.
            final String finalAuthToken = authToken;
            Interceptor headerAuthorizationInterceptor = new Interceptor() {
                @Override
                public okhttp3.Response intercept(Chain chain) throws IOException {
                    okhttp3.Request request = chain.request();
                    Headers headers = request.headers().newBuilder().add("Authorization", finalAuthToken).build();
                    request = request.newBuilder().headers(headers).build();
                    return chain.proceed(request);
                }
            };
    
            //Add the interceptor to the client builder.
            clientBuilder.addInterceptor(headerAuthorizationInterceptor);
    
            return new Retrofit.Builder().baseUrl(baseUrl)
                    .addConverterFactory(GsonConverterFactory.create())
                    .client(clientBuilder.build())
                    .build();
        }
    
        //Get API Service
        public static FloorplansApiService getApiService(Context context) {
            return getRetrofitInstance(context).create(FloorplansApiService.class);
        }
    }
    

    现在它可以工作了!谢谢大家!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-06-07
      • 1970-01-01
      • 2016-01-11
      • 1970-01-01
      • 2019-01-19
      • 2015-04-07
      • 1970-01-01
      • 2019-10-01
      相关资源
      最近更新 更多