recyclerView missing error in Android Studio

Viewed 49

I'm a beginner programmer and I'm trying to receive data from the server using node.js and display the list on Android Studio but I keep having the following error:

E/RecyclerView: No adapter attached; skipping layout
D/HistoryActivity: HistoryResponse{result=[com.sooryong.loginexample.data.HistoryData@3303f3c, com.sooryong.loginexample.data.HistoryData@33764c5]}
D/AndroidRuntime: Shutting down VM

As you can see, I can't recall my list properly as well and I don't know how to fix it. Here are my codes:

public interface ServiceApi {
    @POST("/user/login")
    Call<LoginResponse> userLogin(@Body LoginData data);

    @POST("/user/join")
    Call<JoinResponse> userJoin(@Body JoinData data);

    @GET("/test/history")
    Call<HistoryResponse> getData();
}

HistoryData.java

public class HistoryData {

    @SerializedName("eventID")
    private int eventID;

    @SerializedName("eventType")
    private String eventType;

    @SerializedName("eventDate")
    private String eventDate;

    @SerializedName("userID")
    private int userID;

    @SerializedName("sensorID")
    private String sensorID;

    public HistoryData(int eventID, String eventType, String eventDate, int userID, String sensorID) {
        super();
        this.eventID = eventID;
        this.eventType = eventType;
        this.eventDate = eventDate;
        this.userID = userID;
        this.sensorID = sensorID;
    }

    public int getEventID() {
        return eventID;
    }

    public String getEventType() {
        return eventType;
    }

    public String getEventDate() { return eventDate; }

    public int getUserID() {
        return userID;
    }

    public String getSensorID() { return sensorID; }

}

HistoryResponse.java

public class HistoryResponse {
    @SerializedName("code")
    public String code;

    @SerializedName("message")
    public String message;

    @SerializedName("result")
    public List<HistoryData> result;

    @Override
    public String toString() {

        return "HistoryResponse{" + "result=" + result +'}';
    }

}

HistoryActivity.java

public class HistoryActivity extends AppCompatActivity {

    HistoryResponse dataList;

    List<HistoryData> dataInfo;

    private RecyclerView recyclerView;
    private RecyclerAdapter recyclerAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.recycler_view);

        dataInfo = new ArrayList<>();
        recyclerView = findViewById(R.id.recyclerView);

        RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(layoutManager);

        ServiceApi apiInterface = RetrofitClient.getClient().create(ServiceApi.class);

        Call<HistoryResponse> call = apiInterface.getData();

        call.enqueue(new Callback<HistoryResponse>() {
            @Override
            public void onResponse(Call<HistoryResponse> call, Response<HistoryResponse> response) {

                dataList = response.body();

                Log.d("Response", dataList.toString());

                dataInfo = dataList.result;

                recyclerAdapter = new RecyclerAdapter(getApplicationContext(), dataInfo);
                recyclerView.setAdapter(recyclerAdapter);
            }

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

                Log.d("Response", t.getMessage());
            }
        });
    }

}

RecyclerAdapter.java

public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.MyViewHolder>{

    private Context c;
    private List<HistoryData> dataList;

    public RecyclerAdapter(Context c, List<HistoryData> dataList) {
        this.c = c;
        this.dataList = dataList;
    }

    @NonNull
    @Override
    public RecyclerAdapter.MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {

        View view = LayoutInflater.from(c).inflate(R.layout.recycler_view, parent, false);
        return new MyViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerAdapter.MyViewHolder holder, int position) {

        holder.id.setText(dataList.get(position).getSensorID());
        holder.type.setText("" + dataList.get(position).getEventType());
        holder.date.setText("" + dataList.get(position).getEventDate());

    }

    @Override
    public int getItemCount() {
        return (dataList == null) ? 0 : dataList.size();
    }

    public class MyViewHolder extends RecyclerView.ViewHolder {

        TextView id;
        TextView type;
        TextView date;

        public MyViewHolder(@NonNull View itemView) {
            super(itemView);

            id = (TextView)itemView.findViewById(R.id.sensorID);
            type = (TextView)itemView.findViewById(R.id.eventType);
            date = (TextView)itemView.findViewById(R.id.eventDate);

        }
    }
}

I don't think the data is being initialized properly inside the RecyclerAdapter class. Is it because I couldn't load the data properly from the server?

1 Answers

I ever face the same issue similiar to this. What I've done was: initialize the adapter once only the activity created:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.recycler_view);

    dataInfo = new ArrayList<>();
    
    initAdapter();
    ....
}

private void initAdapter() {
    //The adapter should create once in onCreate

    recyclerView = findViewById(R.id.recyclerView);
    recyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext, LinearLayoutManager.VERTICAL, false);
    recyclerAdapter = new RecyclerAdapter(getApplicationContext(), dataInfo);
    recyclerView.setAdapter(recyclerAdapter);
}

Then when in callback result: you can clear the previous data before reload to the adapter:

call.enqueue(new Callback<HistoryResponse>() {
        @Override
        public void onResponse(Call<HistoryResponse> call, Response<HistoryResponse> response) {
            dataList = response.body();

            dataInfo.clear(); // <- here we clear all previous data before reload result to the adapter.
            dataInfo = dataList.result;
            recyclerAdapter.notifyDataSetChanged()

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

Hope this help.

Related