【问题标题】:How to parse newline delimited Json response in Android?如何在 Android 中解析换行符分隔的 Json 响应?
【发布时间】:2015-10-18 18:48:37
【问题描述】:

NdJson 数据示例:

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

这是我的 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) {}

         });

我的模型课

模型类只有两个参数:

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

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

API 类

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

@GET("/search?limit=1") 替换为@GET("/search") 时遇到的错误是Malformed JSON: Syntax error

问题

如何正确解析NdJson

有没有办法将响应存储在List&lt;APIData&gt;

编辑-1

现在我正在尝试在观察者中接受通用 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) {}
 });

但是得到no suitable method found for subscribe(&lt;anonymous Observer&lt;Response&gt;&gt;)

编辑-2

但是,我犯了一些愚蠢的错误,我在“Edit-1”部分遇到的错误现在已修复。现在我得到了

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 $

【问题讨论】:

  • 为什么 type 和 id 是静态的?你可以重新发布模型吗?
  • @Blackbelt 我编辑了问题
  • 接收 json 作为字符串怎么样。将其拆分为 response.split("\n") 之类的数组。只需遍历它并使用 gson 创建新对象?
  • @ProblemSlover 想象一下,我在一个响应中确实有 2000 个分隔符。运行循环会很耗时(这是我需要在 android 中显示的第一个活动)
  • 我会得到一个Response,然后将其拆分为\n,然后使用平面图将每个APIData 作为流的一个事件

标签: java android json gson retrofit


【解决方案1】:

为了让事情顺利进行,我必须通过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();
}
}

而且效果很好!

【讨论】:

  • 这正是我的意思。这是我第二次追随我的疑问,没有包括我的答案!
  • 你只是得到一个字符串,在这里。不需要自定义转换器。
【解决方案2】:

我假设服务器响应具有以下格式

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

基本思想是接收来自服务器的响应作为字符串。将其拆分为response.split("\n") 之类的数组。遍历一个数组,为每个数组元素创建一个新的 json 对象。

我确实意识到,正如您在 cmets 中所描述的那样,这非常耗时。您还可以尝试使用 String replaceAll 方法将每一行转换为数组元素并解析整个字符串。喜欢

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

在改造的情况下。您将不得不使用自定义响应转换器。 我不会写完整的解决方案,因为您已经找到了使用自定义转换器完成它的方法。

【讨论】:

  • 请在问题部分查看我的评论。迭代会更耗时,我们能不能用更好的方式来做,即将所有字符串存储在List&lt;my model object&gt;
  • 当我处理正常的 REST 调用而不是 Reactive/Rx-java 和 android 中的改造时,你的答案是完美的
  • 我看不到您之前建议使用自定义转换器的评论。我只是想赞成它:D
  • @AmitPal 请接受我的回答,您将获得更多 2 分。我将获得几个小时的研究奖励:P 开玩笑。小鬼。声望10就够了。即使我今天的目标是达到400:P
  • 大声笑。你刚刚达到 400 :P
【解决方案3】:

对于初学者来说,你的json不是Gson能理解的json,所以不能直接在Retrofit中使用Gson转换器。所以

public Observable<APIData> getdata ();

必须

public Observable<Response> getdata ();

那么,你有

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();
       });
   });

您可以订阅它并接收您的 json 列表中的每一项。

这没有经过测试,也没有处理错误情况(为了简短,也没有测试订阅的有效性)。

不过,大体上应该朝着正确的方向发展。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-01-26
    • 1970-01-01
    • 1970-01-01
    • 2021-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多