0

I want to fetch json from a url https://api.myjson.com/bins/mxcsl/ using retrofit and rxjava. Sample json is this :

{
"data": [
{
  "itemId": "1",
  "desc": "Batcave",
  "audio": "https://storage.googleapis.com/a/17.mp3"
},
{
  "itemId": "2",
  "desc": "Fight Club rules",
  "audio": "https://storage.googleapis.com/a/2514.mp3"
},
{
  "itemId": "3",
  "desc": "Make an offer",
  "audio": "https://storage.googleapis.com/a/47.mp3"
}]}

And here is my code : Data Model :

public class Data {

private String itemId;
private String desc;
private String audio;

public String getItem() {
    return itemId;
}

public String getDesc() {
    return desc;
}

public String getAudio() {
    return audio;
}}

This is the Interface :

public interface RequestInterface {

@GET("/bins/mxcsl/")
Observable<List<Data>> register();

}

I'm loading something like this :

private void loadJSON() {


    RequestInterface requestInterface = new Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .addConverterFactory(GsonConverterFactory.create())
            .build().create(RequestInterface.class);

    mCompositeDisposable.add(requestInterface.register()
            .observeOn(AndroidSchedulers.mainThread())
            .subscribeOn(Schedulers.io())
            .subscribe(this::handleResponse,this::handleError));
}

private void handleResponse(List<Data> androidList) {

    mAndroidArrayList = new ArrayList<>(androidList);
    mAdapter = new DataAdapter(mAndroidArrayList);
    mRecyclerView.setAdapter(mAdapter);
}

private void handleError(Throwable error) {

    Toast.makeText(this, "Error "+error.getLocalizedMessage(), Toast.LENGTH_SHORT).show();
}

But Also I'm getting the error expected BEGIN_ARRAY but was BEGIN_OBJECT

I don't know where this is going wrong. Please help.

Saket Kumar
  • 463
  • 8
  • 22

3 Answers3

3

Your type

Observable<List<Data>> register();

is wrong. Because Json's first level is not Array (But object with field data, that is array). You should create class for outer structure

public class Outer{
    List<Data> data;
}

And specify in retrofit, as observable:

@GET("/bins/mxcsl/")
Observable<Outer> register();
Misha Akopov
  • 12,241
  • 27
  • 68
  • 82
  • My handleResponse is this : private void handleResponse(List androidList) { mAndroidArrayList = new ArrayList<>(androidList); mAdapter = new DataAdapter(mAndroidArrayList); mRecyclerView.setAdapter(mAdapter); } How to change this ? – Saket Kumar Jul 20 '18 at 18:09
  • 1
    Like this, this will be your method: private void handleResponse(Outer response) inside it you can get list as: mAndroidArrayList = response.data And everything else will be the same – Misha Akopov Jul 20 '18 at 18:13
2

Your api response is a JSONObject which contain a JSONArray with key data.

Wrap your List of Data with another Model class

public class ResponseData {

  @SerializedName("data")
  private List<Data> dataList;

  public List<Data> getDataList() {
    return dataList;
  }

  public void setDataList(List<Data> list) {
    dataList = list;
  }

}

Use ResponseData class in RequestInterface

public interface RequestInterface {

  @GET("/bins/mxcsl/")
  Observable<ResponseData> register();

}

Added:

As your converted Response is ResponseData object so your handleResponse method parameter would be ResponseData type. In handleResponse get your expected list from getter method and set it to Adapter.

handleResponse method

private void handleResponse(ResponseData responseData) {
  if( responseData != null){
     List<Data> dataList = responseData.getDataList();
     mAndroidArrayList = new ArrayList<>();
     if(dataList!= null){
        mAndroidArrayList.addAll(dataList);
     }
     mAdapter = new DataAdapter(mAndroidArrayList);
     mRecyclerView.setAdapter(mAdapter);
 }
}
Abu Yousuf
  • 5,729
  • 3
  • 31
  • 50
  • My handleResponse is this : private void handleResponse(List androidList) { mAndroidArrayList = new ArrayList<>(androidList); mAdapter = new DataAdapter(mAndroidArrayList); mRecyclerView.setAdapter(mAdapter); } How to change this ? – Saket Kumar Jul 20 '18 at 18:08
0

The error is because Retrofit is expecting a json array to be deserialized as a List

public interface RequestInterface {

    @GET("/bins/mxcsl/")
    Observable<List<Data>> register();
}

But the json response is an object with a field named data that is an array

{
 "data": [
 {
  "itemId": "1",
  "desc": "Batcave",
  "audio": "https://storage.googleapis.com/a/17.mp3"
 },
 {
  "itemId": "2",
  "desc": "Fight Club rules",
  "audio": "https://storage.googleapis.com/a/2514.mp3"
 },
 {
  "itemId": "3",
  "desc": "Make an offer",
  "audio": "https://storage.googleapis.com/a/47.mp3"
}]}
Facundo Larrosa
  • 3,349
  • 2
  • 14
  • 22