Saket Kumar
Saket Kumar

Reputation: 463

Fetch JSON data using retrofit and rxjava

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.

Upvotes: 0

Views: 1478

Answers (3)

Abu Yousuf
Abu Yousuf

Reputation: 6142

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

Upvotes: 2

Facundo Larrosa
Facundo Larrosa

Reputation: 3389

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"
}]}

Upvotes: 0

Misha Akopov
Misha Akopov

Reputation: 13057

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

Upvotes: 3

Related Questions