简体   繁体   English

如何在Android中解析以换行符分隔的Json响应?

[英]How to parse newline delimited Json response in Android?

Sample of NdJson data: NdJson数据样本:

{"type":"data","id":"xyz"}
{"type":"value","id":"xcf"}
....
....

Here is my Retrofit and RxJava code which is working fine for fetching data with the limit=1 ie {"type":"data","id":"xyz"} . 这是我的RetrofitRxJava代码,适用于以limit=1{"type":"data","id":"xyz"}来获取数据。

 adapter.create(API.class).getData()
        .subscribeOn(Schedulers.newThread())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Observer<APIData>() {
         @Override
         public void onCompleted() {}

         @Override
         public void onError(Throwable e) {}

         @Override
         public void onNext(APIData apidata) {}

         });

My model class 我的模特班

Model class have only two parameter: 模型类只有两个参数:

public class APIData(){
  private String type;
  private String id;

  ..// Getter and setter for above two fields
}

Api class api类

public interface WarehouseAPI {
  @GET("/search?limit=1")
  public Observable<APIData> getdata ();
}

The error I am getting while replacing @GET("/search?limit=1") with @GET("/search") is Malformed JSON: Syntax error . 而更换我正的错误@GET("/search?limit=1")@GET("/search")Malformed JSON: Syntax error

Question

How to proper parse the NdJson ? 如何正确解析NdJson

Is there any way to store the response in List<APIData> 有什么方法可以将响应存储在List<APIData>

Edit-1 编辑-1

Now I am trying to accept the generic Response in observer: 现在,我试图在观察者中接受通用Response

adapter.create(APIData.class).getdata()
       .subscribeOn(Schedulers.newThread())
       .observeOn(AndroidSchedulers.mainThread())
       .subscribe(new Observer<Response>() {
        @Override
        public void onCompleted() {}

        @Override
        public void onNext(Response response) {}
 });

But getting no suitable method found for subscribe(<anonymous Observer<Response>>) 但是no suitable method found for subscribe(<anonymous Observer<Response>>)

Edit-2 编辑-2

However, I was doing some silly mistake and the error what I am getting in "Edit-1" section is fixed now. 但是,我犯了一些愚蠢的错误,并且在“ Edit-1”部分中得到的错误现在已修复。 Now I am getting 现在我得到

Error:retrofit.RetrofitError: com.google.gson.JsonSyntaxException: com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line 2 column 2 path $

I assume that server response has the following format 我假设服务器响应具有以下格式

{"type":"data","id":"xyz"}\n{"type":"data","id":"xyz"}

The basic idea is to receive the response from the server as the String. 基本思想是从服务器接收响应作为字符串。 Split it into array like response.split("\\n") . 将其拆分为类似于response.split("\\n")数组。 Iterate through an Array creating a new json object for every array element. 遍历数组,为每个数组元素创建一个新的json对象。

I do realize it's quite time consuming as you've described in the comments. 我确实意识到,正如您在评论中所描述的那样,这非常耗时。 You can also try to play with String replaceAll method to transform each line into an array element and parse the whole string. 您也可以尝试使用String replaceAll方法将每一行转换成一个数组元素并解析整个字符串。 like 喜欢

String myResponse = "[" + response.replaceAll("/\n/", ",") + "]";
Gson gson = new Gson();
MyEntity[] arr = gson.fromJson(myResponse, MyEntity[].class);

In case of Retrofit. 如果进行改装。 You will have to use a custom Response Converter. 您将必须使用自定义响应转换器。 I won't write up the complete solution since you have found the way to get it done using custom Converter. 因为您已经找到了使用自定义Converter来完成该问题的方法,所以我不会写出完整的解决方案。

To make things work I had to add Custom converter implements by Retrofit.Converter : 为了使工作正常,我必须通过Retrofit.Converter添加Custom converter工具:

public class CustomConverter implements Converter {

@Override
public Object fromBody(TypedInput body, Type type) throws ConversionException {
    String text = null;
    try {
        text = fromStream(body.in());
    } catch (IOException e) {
        e.printStackTrace();
    }
    return text;

}

@Override
public TypedOutput toBody(Object object) {
    return null;
}

// Custom method to convert stream from request to string
public static String fromStream(InputStream in) throws IOException {
    BufferedReader reader = new BufferedReader(new InputStreamReader(in));
    StringBuilder out = new StringBuilder();
    String newLine = System.getProperty("\n");
    String line;
    while ((line = reader.readLine()) != null) {
        out.append(line);
        out.append(newLine);
    }
    return out.toString();
}
}

And it works perfectly! 而且效果很好!

For starters, your json is not json that Gson understand, so you can't use the Gson converter in Retrofit directly. 对于初学者,您的json并不是Gson可以理解的json,因此您不能直接在Retrofit中使用Gson转换器。 So 所以

public Observable<APIData> getdata ();

must be 一定是

public Observable<Response> getdata ();

Then, you have 那你有

adapter.create(WarehouseAPI.class).getdata()
   .subscribeOn(Schedulers.newThread())
   .observeOn(AndroidSchedulers.mainThread())
   .map((Response res) -> new BufferedStreamReader(res.body.body().bytesStream()))
   .flatMap(stream -> {
       return Observable.create(subscriber -> {
           String line;
           while((line = stream.readLine() != null) {
               subscriber.onNext(gson.fromJson(line, APIData.class));
           }
           subscriber.onCompleted();
       });
   });

You can subscribe to that and receive each individual item of your json list. 您可以订阅它,并接收json列表中的每个项目。

This is not tested, and error cases are not handled (and validity of subscription is not tested, for shortness). 这未经测试,错误情况也未得到处理(为简短起见,未测试订阅的有效性)。

It should mostly be in the right direction though. 不过,它基本上应该朝着正确的方向发展。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM