0
votes

While using the Spotify search API, I want to receive a list of albums back. However, there is always an error about it expecting an array but getting an object. However in my code, I have set the type as array only. So I don't know where I am going wrong.

This is the Spotify documentation- https://developer.spotify.com/documentation/web-api/reference/search/search/

Main Activity(I get static TOKEN from loginactivity)

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

        mSearchEditText = findViewById(R.id.search_edittext);
        mSearchButton = findViewById(R.id.search_button);
        mTestTextView = findViewById(R.id.test_textview);
        mAlbumList = new ArrayList<>();
        mAlbum = new Album();

        retrofitOperations();

        mSearchButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                if (mSearchEditText.getText() != null) {
                    searchForArt(mSearchEditText.getText().toString());
                }
            }
        });

    }

    private void searchForArt(String text) {

        text = text.replace(" ", "&20");
        HashMap<String, String> parameters = new HashMap<>();
        parameters.put("Authorization", "Bearer " + TOKEN);

        Call<Album> call = mSpotifyService.getAlbum(text, "album", parameters);
        Log.d(TAG, "searchForArt: started call");
        call.enqueue(new Callback<Album>() {
            @Override
            public void onResponse(@NonNull Call<Album> call, @NonNull Response<Album> response) {

                if (!response.isSuccessful()) {

                    Toast.makeText(MainActivity.this, "Response not successful", Toast.LENGTH_SHORT).show();
                    Log.d(TAG, "onResponse: not successful");
                    return;

                }

                Log.d(TAG, "onResponse: successful");
                mTestTextView.setText(null);
                mAlbum = response.body();
                //for (Album album : mAlbumList) {

                List<Item> itemList = mAlbum.getItemList();

                for (Item item : itemList) {

                    List<Image> imageList = item.getImageList();

                    for (Image image : imageList) {

                        mTestTextView.append(image.getUrl() + "\n");

                    }

                }
                // }

            }

            @Override
            public void onFailure(Call<Album> call, Throwable t) {

                Toast.makeText(MainActivity.this, t.getMessage(), Toast.LENGTH_SHORT).show();
                Log.d(TAG, "onFailure: call failure " + t.getMessage());

            }
        });

    }

    private void retrofitOperations() {

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://api.spotify.com/v1/")
                .addConverterFactory(GsonConverterFactory.create())
                .build();

        mSpotifyService = retrofit.create(SpotifyService.class);

    }

SpotifyService interface

public interface SpotifyService {

    @GET("search")
    Call<Album> getAlbum(@Query("q") String q,
                         @Query("type") String type,
                         @HeaderMap Map<String,String> headers);

}

Album class

public class Album implements Parcelable {

    @SerializedName("items")
    private List<Item> itemList;

    public Album() {
    }

    public List<Item> getItemList() {
        return itemList;
    }

    protected Album(Parcel in) {
        itemList = in.createTypedArrayList(Item.CREATOR);
    }

    public static final Creator<Album> CREATOR = new Creator<Album>() {
        @Override
        public Album createFromParcel(Parcel in) {
            return new Album(in);
        }

        @Override
        public Album[] newArray(int size) {
            return new Album[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeTypedList(itemList);
    }
}

Item class

public class Item implements Parcelable {

    @SerializedName("images")
    private List<Image> imageList;

    public Item() {
    }

    public List<Image> getImageList() {
        return imageList;
    }

    public void setImageList(List<Image> imageList) {
        this.imageList = imageList;
    }

    protected Item(Parcel in) {
    }

    public static final Creator<Item> CREATOR = new Creator<Item>() {
        @Override
        public Item createFromParcel(Parcel in) {
            return new Item(in);
        }

        @Override
        public Item[] newArray(int size) {
            return new Item[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
    }
}

Image class

public class Image implements Parcelable{

    @SerializedName("url")
    private String url;

    public Image() {
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    protected Image(Parcel in) {
        url = in.readString();
    }

    public static final Creator<Image> CREATOR = new Creator<Image>() {
        @Override
        public Image createFromParcel(Parcel in) {
            return new Image(in);
        }

        @Override
        public Image[] newArray(int size) {
            return new Image[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(url);
    }
}

Error

2020-04-07 17:57:55.945 21128-21128/com.example.spotify_album_art E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.spotify_album_art, PID: 21128
    java.lang.NullPointerException: Attempt to invoke interface method 'java.util.Iterator java.util.List.iterator()' on a null object reference
        at com.example.spotifyalbumart.MainActivity$2.onResponse(MainActivity.java:96)
        at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall$1$1.run(ExecutorCallAdapterFactory.java:70)
        at android.os.Handler.handleCallback(Handler.java:883)
        at android.os.Handler.dispatchMessage(Handler.java:100)
        at android.os.Looper.loop(Looper.java:214)
        at android.app.ActivityThread.main(ActivityThread.java:7356)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
1

1 Answers

1
votes

There is a problem with your response that you get while in API call. In API that returns just object of your Album class not List<Album>.

So just do like below is a request for API.

Call<Album> call = mSpotifyService.getAlbum(text, "album", parameters);
        Log.d(TAG, "searchForArt: started call");
        call.enqueue(new Callback<Album>() {
            @Override
            public void onResponse(Call<Album> call, Response<Album> response) {

            }

            @Override
            public void onFailure(Call<Album> call, Throwable t) {

                Toast.makeText(MainActivity.this, t.getMessage(), Toast.LENGTH_SHORT).show();
                Log.d(TAG, "onFailure: call failure "+t.getMessage());

            }
        });

And in your interface like

@GET("search")
    Call<Album> getAlbum(@Query("q") String q,
                               @Query("type") String type,
                               @HeaderMap Map<String,String> headers);