为什么JSON文档没有被完全消耗?

9
我正在练习从外部源检索JSON数据。我已经完成了所有代码,但出现了一个错误,提示文档没有完全消耗。我观看了多个教程和指南,但仍然无法解决问题。我也在stack上搜寻答案,但由于我不知道哪里出了问题,所以我不知道该搜寻什么。
所有的代码都已经准备就绪,也没有明显的错误。JSON数据已经过验证,并且可以作为原始JSON数据进行检索,如日志中所示。问题出现在Gson转换时,当数据应该传递到Java数据类时。有任何建议吗?
public class JSONimport extends AsyncTask<Void, Void, DeserializedContainer> {

private static final String TAG = "TAG";

//VARIABLES TO HOLD JSON DATA
private OnLoadListener mListener;


//CONSTRUCTOR
public JSONimport(OnLoadListener listener) {
    this.mListener = listener;
}

//ASYNK, DO IN BACKGROUND THREAD
@Override
protected DeserializedContainer doInBackground(Void... voids) {
    String myJSON = ""; //TEMP VARIABLE TO HOLD JSON DATA
    String completeJSONdata = ""; //VARIABLE TO HOLD COMPLETE JSON DATA

    try {
        URL urlObject = new URL( "https://api.myjson.com/bins/161kkd" );
        HttpURLConnection httpURLConnection = (HttpURLConnection) urlObject.openConnection();
        InputStream inputStreamObject = httpURLConnection.getInputStream();
        BufferedReader bufferedReaderObject = new BufferedReader( new InputStreamReader( inputStreamObject ) );

        while (myJSON != null) {
            myJSON = bufferedReaderObject.readLine();
            completeJSONdata += myJSON;
        }

    } catch (MalformedURLException e) {
        e.printStackTrace();
        Log.d( TAG, "doInBackground: ERROR RETRIEVING URL" );
    } catch (IOException e) {
        e.printStackTrace();
        Log.d( TAG, "doInBackground: ERROR HTTP CONNECTION" );
    }


    //DESERIALIZATION, converting JSON to java variables, making the data easy to handle
    Gson gsonObject = new GsonBuilder()
            .setLenient()
            .create();
    DeserializedContainer deserializedContainerObject;

    deserializedContainerObject = gsonObject.fromJson( completeJSONdata, DeserializedContainer.class );
    //Log.d( TAG, "doInBackground: " + deserializedContainerObject.getDeserializedContainerList() );


    return deserializedContainerObject;
}

@Override
protected void onPostExecute(final DeserializedContainer result) {

    mListener.onSuccess( result );
    //FUNKAR ATT HÄMTA JSON DATA. KOLLA LOGCAT
    Log.d( TAG, "onPostExecuteLOL: " + result );
}

public static interface OnLoadListener {
    void onSuccess(DeserializedContainer container);
}}

错误出现在deserializedContainerObject = gsonObject.fromJson(completeJSONdata, DeserializedContainer.class);

用于保存JSON数据的数据对象:

public class DeserializedContainer {
@SerializedName("deserializedContainerList")
public List<DeserializedVariables> deserializedContainerList = new ArrayList<>();

public List<DeserializedVariables> getDeserializedContainerList() {
    return deserializedContainerList;
}}

public class DeserializedVariables {
@SerializedName( "movieName" )
private String movieName;
@SerializedName( "movieYear" )
private int movieYear;
@SerializedName( "movieRating" )
private double movieRating;}

主线程的相关数据:

public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate( savedInstanceState );
    setContentView( R.layout.activity_main );

    //BACKGROUND THREAD
    JSONimport jsonImportObject = new JSONimport( new JSONimport.OnLoadListener() {
        @Override
        public void onSuccess(DeserializedContainer container) {
            container.getDeserializedContainerList();
        }
    } );
    jsonImportObject.execute();

    //Log.d( TAG, "onCreateGETTING DATA : " + jsonImportObject.getCompletedData());

    DeserializedContainer deserializedContainerObject = new DeserializedContainer();
    Log.d( TAG, "onCreate: " + deserializedContainerObject);

JSON:

{"deserializedContainerList":[{"movieName":"filmA","movieYear":2017,"movieRating":4.7},{"movieName":"filmB","movieYear":2018,"movieRating":4.8},{"movieName":"filmC","movieYear":2019,"movieRating":4.9}]}

很抱歉这篇文章很长,希望你有精力阅读。我遇到了困难。虽然我知道Retrofit和类似的库,但我已经花了很多时间来解决这个问题,所以我不想放弃它 :P

谢谢!

/////// 更新 /////// 我根据Laurent B的建议更新了代码,并且它起作用了!或者说至少没有崩溃。我尝试使用以下代码在主线程上打印列表:

for(int i = 0; i < deserializedContainerObject.deserializedContainerList.size(); i++) {
        Log.d( TAG, "onCreate: " + deserializedContainerObject.deserializedContainerList.get( i ));

    }

但是没有任何显示。当检查deserializedContainerObject.deserializedContainerList.size()时,它显示为0。也就是说,没有数据被添加到列表中... 嗯。至少由于Laurent B的帮助,它没有崩溃,离成功又近了一步。


你是否在onSuccess方法的DeserializedContainer container中检查了对象?deserializedContainerObjectonSuccess方法之外声明,因此它的列表大小为0是有道理的。 - Dave Thomas
@Joakim Sjöstedt,请检查我的答案。 - Vikas singh
3个回答

1
你的完整JSON数据不正确,因为你总是在末尾放置“null”。 相反,你的while条件应该是例如:
        while ((myJSON = bufferedReaderObject.readLine()) != null) {
            completeJSONdata += myJSON;
        }

顺便提一下,不要忘记关闭流,例如使用try-with语句:

try (InputStream inputStreamObject = httpURLConnection.getInputStream()) {
// ...
}

天哪!它不再崩溃了 :) 它工作了!非常感谢Laurent!然而,似乎出现了一个新问题 - 请看主线程的结尾。 - Joakim Sjöstedt

1
数值正在传递,但是 null 也随之传递,因此请使用 if 语句而不是 while,像这样...
if (myJSON != null) {
                myJSON = bufferedReaderObject.readLine();
                completeJSONdata += myJSON;
            }

然后像这样转换为 Gson..
    Gson gson = new Gson();
    deserializedContainerObject = gson.fromJson(completeJSONdata, DeserializedContainer.class);

DeserializedVariables类中编写getter和setter。

public String getMovieName() {
         return movieName;
     }

     public void setMovieName(String movieName) {
         this.movieName = movieName;
     }

     public Integer getMovieYear() {
         return movieYear;
     }

     public void setMovieYear(Integer movieYear) {
         this.movieYear = movieYear;
     }

     public Double getMovieRating() {
         return movieRating;
     }

     public void setMovieRating(Double movieRating) {
         this.movieRating = movieRating;
     }

现在,您可以像这样在onPostExecute()中检索它。

@Override
    protected void onPostExecute( DeserializedContainer result) {

        mListener.onSuccess( result );

        for (int i = 0; i <result.deserializedContainerList.size(); i++) {
            DeserializedVariables deserializedVariables = result.deserializedContainerList.get(i);
            Log.d( TAG, "onPostExecuss: " + deserializedVariables.getMovieName() );
        }

    }

太棒了!终于成功了!非常感谢Visas Singh和Laurent B的帮助!现在我可以继续我的项目了,耶! :D :D :D - Joakim Sjöstedt

0
对于仍然遇到这个异常的人们:对 JSON 进行漂亮打印是我找到的唯一解决方案,然后再将其提供给 Gson(我猜想格式本身可能有问题,尽管没有抛出 JsonMalformattedError 异常)。以下是对我有效的代码:
val jsonPretty = JSONObject(jsonString).toString(2)

你可以将jsonPretty作为字符串传递给Gson。这样GSON就能完整地解析JSON文档了。我相信该库在处理非常不连贯的JSON时会遇到困难(例如,当有太多空格或其他情况时)。我不确定原因,但至少对我来说这种方法有效。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接