Alexander Bayerl Alexander Bayerl - 4 months ago 58
JSON Question

IllegalStateException when trying to parse JSON Feed with retrofit

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!

Answer

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