0

I'm trying to display my feed with CardViews in my Recyclerview using JSON and the Retrofit library. I have been working on this problem for 4 hours and 1 hour searching google now, but still, to no success.

No matter what I try I get the following error:

D/Error: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2 path $ D/Error: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2 path $


JSON Example from PHP API:

[{"id":"143","uploadID":"36","type":"excellent","userID":"58","username":"doitlikeaves","date":"31 May","timestamp":"2016-05-31 22:37:50","title":"PH Zusammenfassung #2","subject":"Physik"},{"id":"142","uploadID":"36","type":"presentation","userID":"58","username":"doitlikeaves","date":"31 May","timestamp":"2016-05-31 21:57:21","title":"PH Zusammenfassung #2","subject":"Physik"},{"id":"141","uploadID":"61","type":"document","userID":"56","username":"maja","date":"31 May","timestamp":"2016-05-31 14:29:00","title":" Rev.","subject":"Geschichte"}]


Android Files:

FeedElement.js:

import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;

public class FeedElement {

    @SerializedName("id")
    @Expose
    private String id;
    @SerializedName("uploadID")
    @Expose
    private String uploadID;
    @SerializedName("type")
    @Expose
    private String type;
    @SerializedName("userID")
    @Expose
    private String userID;
    @SerializedName("username")
    @Expose
    private String username;
    @SerializedName("date")
    @Expose
    private String date;
    @SerializedName("timestamp")
    @Expose
    private String timestamp;
    @SerializedName("title")
    @Expose
    private String title;
    @SerializedName("subject")
    @Expose
    private String subject;

    /**
     *
     * @return
     * The id
     */
    public String getId() {
        return id;
    }

    /**
     *
     * @param id
     * The id
     */
    public void setId(String id) {
        this.id = id;
    }

    /**
     *
     * @return
     * The uploadID
     */
    public String getUploadID() {
        return uploadID;
    }

    /**
     *
     * @param uploadID
     * The uploadID
     */
    public void setUploadID(String uploadID) {
        this.uploadID = uploadID;
    }

    /**
     *
     * @return
     * The type
     */
    public String getType() {
        return type;
    }

    /**
     *
     * @param type
     * The type
     */
    public void setType(String type) {
        this.type = type;
    }

    /**
     *
     * @return
     * The userID
     */
    public String getUserID() {
        return userID;
    }

    /**
     *
     * @param userID
     * The userID
     */
    public void setUserID(String userID) {
        this.userID = userID;
    }

    /**
     *
     * @return
     * The username
     */
    public String getUsername() {
        return username;
    }

    /**
     *
     * @param username
     * The username
     */
    public void setUsername(String username) {
        this.username = username;
    }

    /**
     *
     * @return
     * The date
     */
    public String getDate() {
        return date;
    }

    /**
     *
     * @param date
     * The date
     */
    public void setDate(String date) {
        this.date = date;
    }

    /**
     *
     * @return
     * The timestamp
     */
    public String getTimestamp() {
        return timestamp;
    }

    /**
     *
     * @param timestamp
     * The timestamp
     */
    public void setTimestamp(String timestamp) {
        this.timestamp = timestamp;
    }

    /**
     *
     * @return
     * The title
     */
    public String getTitle() {
        return title;
    }

    /**
     *
     * @param title
     * The title
     */
    public void setTitle(String title) {
        this.title = title;
    }

    /**
     *
     * @return
     * The subject
     */
    public String getSubject() {
        return subject;
    }

    /**
     *
     * @param subject
     * The subject
     */
    public void setSubject(String subject) {
        this.subject = subject;
    }

}

JSONResponseFeed.js:

import java.util.ArrayList;
public class JSONResponseFeed {
    private ArrayList<FeedElement> feeds;

    /**
     * @return The feeds
     */
    public ArrayList<FeedElement> getFeed() {
        return feeds;
    }
}

RequestInterfaceFeed.js:

import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Query;

public interface RequestInterfaceFeed {
    @GET("getFeed")
    Call<JSONResponseFeed> getJSON(@Query("key") String apiKey);
}

DataAdapterFeed.js:

import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import java.util.List;

public class DataAdapterFeed extends RecyclerView.Adapter<DataAdapterFeed.ViewHolder> {
    private List<FeedElement> feed;

public DataAdapterFeed(List<FeedElement> feed) {
    this.feed = feed;
}

@Override
public DataAdapterFeed.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
    View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.card_row, viewGroup, false);
    return new ViewHolder(view);
}

@Override
public void onBindViewHolder(DataAdapterFeed.ViewHolder viewHolder, int i) {

    viewHolder.tv_name.setText(feed.get(i).getUsername());
}

@Override
public int getItemCount() {
    return feed.size();
}

public class ViewHolder extends RecyclerView.ViewHolder{
    private TextView tv_name;
    public ViewHolder(View view) {
        super(view);

        tv_name = (TextView)view.findViewById(R.id.username);

        }
    }
}

Functions from MainActivity.js:

 private void loadJSON(){
    final String url = "https://mydomainiscorrect.justreplacedithere/api/v1/";
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(url)
            .addConverterFactory(GsonConverterFactory.create())
            .build();
    final RequestInterfaceFeed request = retrofit.create(RequestInterfaceFeed.class);
    Call<JSONResponseFeed> call = request.getJSON(apiKey);
    call.enqueue(new Callback<JSONResponseFeed>() {
        @Override
        public void onResponse(Call<JSONResponseFeed> call, retrofit2.Response<JSONResponseFeed> response) {
            List<FeedElement> data = response.body().getFeed();
            adapter = new DataAdapterFeed(data);
            recyclerView.setAdapter(adapter);
        }

        @Override
        public void onFailure(Call<JSONResponseFeed> call, Throwable t) {
            Log.d("Error", t.getMessage());
        }
    });
}

private void initViews(){
    recyclerView = (RecyclerView)findViewById(R.id.card_recycler_view);
    recyclerView.setHasFixedSize(true);
    RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getApplicationContext());
    recyclerView.setLayoutManager(layoutManager);
    loadJSON();
}

If needed - cardView.xml:

<android.support.v7.widget.CardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
card_view:cardCornerRadius="5dp">
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_margin="10dp"
    android:orientation="vertical">
    <TextView
        android:id="@+id/username"
        android:layout_marginTop="10dp"
        android:layout_marginBottom="10dp"
        android:textSize="18sp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textStyle="bold" />
</LinearLayout>


MainActivity RecyclerView XML:

 <android.support.v7.widget.RecyclerView
        android:id="@+id/card_recycler_view"
        android:scrollbars="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>


I'm stil pretty new to Java and Android Programming, I know PHP pretty good, but Java really gives me headaches sometimes.

Thank you a lot for trying to help me, I really appreciate it!

  • 1
    Check this stackoverflow thread, which may help you. http://stackoverflow.com/questions/9598707/gson-throwing-expected-begin-object-but-was-begin-array – lsiva Jul 25 '16 at 17:46
  • @Isiva saw that thread already, but it just made me wonder more, wouldn't know where to put what of what the answer says, don't even know where my code is actually wrong, as my app doesn't crash :/ – Alexander Bayerl Jul 25 '16 at 17:49
  • check my answer http://stackoverflow.com/questions/38418556/expected-begin-array-but-was-begin-object-with-gson-and-retrofit/38418739#38418739 – USKMobility Jul 25 '16 at 18:06
  • Can you provide the actual url so we can test, or is it private? – nasch Jul 25 '16 at 20:30
  • @nasch I'm sorry it is private, but the JSON I posted on the top of this thread is exactly as it is outputted by the server :) – Alexander Bayerl Jul 25 '16 at 20:33
  • I'm thinking you need a custom converter to tell it what to do with the array, but not sure without playing with it. – nasch Jul 25 '16 at 20:34
  • @nasch isn't that what FeedElement.js and the loadJSON function does? – Alexander Bayerl Jul 25 '16 at 22:56
  • Yeah but that's not working. :-) Like I said just a guess. If you want to either set up a public service to serve that json or post code that parses it without the retrofit stuff I'll try to take a look. – nasch Jul 26 '16 at 02:40
  • @nasch I'll put it on another server for you and post the link later :) – Alexander Bayerl Jul 26 '16 at 10:21
  • @nasch here is the URL http://thelix.ml/json.php – Alexander Bayerl Jul 26 '16 at 13:49
  • @USKMobility tried it, but it just gave me errors, would you be so kind and show me, what I'd have to change? You can try it yourself using this link to the example JSON: thelix.ml/json.php – Alexander Bayerl Jul 26 '16 at 18:17

2 Answers2

1

JSONResponseFeed is not required. Update RequestInterfaceFeed

public interface RequestInterfaceFeed {
    @GET("getFeed")
    Call<List<FeedElement>> getJSON(@Query("key") String apiKey);
}

And update loadJSON method

private void loadJSON(){
    final String url = "https://mydomainiscorrect.justreplacedithere/api/v1/";
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(url)
            .addConverterFactory(GsonConverterFactory.create())
            .build();
    final RequestInterfaceFeed request = retrofit.create(RequestInterfaceFeed.class);
    Call<List<FeedElement>> call = request.getJSON(apiKey);
    call.enqueue(new Callback<List<FeedElement>>() {
        @Override
        public void onResponse(Call<List<FeedElement>> call, retrofit2.Response<List<FeedElement>> response) {
            List<FeedElement> data = response.body();
            adapter = new DataAdapterFeed(data);
            recyclerView.setAdapter(adapter);
        }

        @Override
        public void onFailure(Call<List<FeedElement>> call, Throwable t) {
            Log.d("Error", t.getMessage());
        }
    });
}
USKMobility
  • 5,721
  • 2
  • 27
  • 34
0

I have similar things with you ;) But I have list of element by inheritance

public class ListClubs extends LinkedList<Club> {
}

My service looks like :

public interface ClubService {

    @GET("/clubs")
    Call<ListClubs> getClubs();

    @GET("/clubs/{id}")
    Call<ClubDetail> getClub(@Path("id") String id);

}

And this works fine.

If you want that your code works I'm thinking you're JSON must looks like :

{feeds:[{"id":"143","uploadID":"36","type":"excellent","userID":"58","username":"doitlikeaves","date":"31 May","timestamp":"2016-05-31 22:37:50","title":"PH Zusammenfassung #2","subject":"Physik"},{"id":"142","uploadID":"36","type":"presentation","userID":"58","username":"doitlikeaves","date":"31 May","timestamp":"2016-05-31 21:57:21","title":"PH Zusammenfassung #2","subject":"Physik"},{"id":"141","uploadID":"61","type":"document","userID":"56","username":"maja","date":"31 May","timestamp":"2016-05-31 14:29:00","title":" Rev.","subject":"Geschichte"}]}