2

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?

Junaid Khalid
  • 811
  • 2
  • 11
  • 26
  • Change your log to be sure. Change it to: `Log.d("Response", "Success " + dataList.result);` And add a `toString` method to `HistoryData` to see the data properly in the log. – Blundell Apr 03 '22 at 21:44
  • To debug the issue in your `RecyclerAdapter` instantiate the `List` field with some fake data, that will tell you if the problem is in your UI side or your Networking data side. (If you don't see the fake data in the UI, then its a recyclerview/adapter UI problem.) – Blundell Apr 03 '22 at 21:47
  • https://stackoverflow.com/questions/29141729/recyclerview-no-adapter-attached-skipping-layout. Probably you should attach the adapter in `onCreate`, not in `onResponse`. First adapter will be empty, and in `onResponse` you will add items. Also set `layoutManager.setOrientation(LinearLayoutManager.VERTICAL)`. – CoolMind Apr 03 '22 at 21:47

1 Answers1

1

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.

Binz_
  • 21
  • 1