Taufiq Rahman
Taufiq Rahman

Reputation: 5704

Retrofit bad request and RecyclerView: No adapter attached; skipping layout

Hi I am not sure why exactly my recycler view is not displaying but I get the following error even after initializing it on onCreate method as mentioned by other SO users who faced the same problem:

E/RecyclerView: No adapter attached; skipping layout

Also maybe Retrofit is not able to get the data so onResponse is never called hence onFailure is called. I am using an online JSON API. Link: https://reqres.in/api/users?page=1&per_page=3

ApiClient.java

public class ApiClient {
public static final String BASE_URL = "https://reqres.in/api/";
public static Retrofit retrofit = null;

public static Retrofit getApiClient(){
    if(retrofit == null){
        retrofit = new Retrofit.Builder().baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create()).build();
    }
    return retrofit;
}}

DataResponse.java

public class DataResponse {

@SerializedName("page")
private int page;

@SerializedName("per_page")
private int per_page;

@SerializedName("total")
private int total;

@SerializedName("total_pages")
private int total_pages;

@SerializedName("data")
List<Data> data;

public int getPage() {
    return page;
}

public int getPer_page() {
    return per_page;
}

public int getTotal() {
    return total;
}

public int getTotal_pages() {
    return total_pages;
}

public List<Data> getData() {
    return data;
}
}



class Data {

@SerializedName("id")
private int id;

@SerializedName("first_name")
private String first_name;

@SerializedName("last_name")
private String last_name;

@SerializedName("avatar")
private String avatar;

public int getId() {
    return id;
}

public String getFirst_name() {
    return first_name;
}

public String getLast_name() {
    return last_name;
}

public String getAvatar() {
    return avatar;
}
}

ApiInterface

public interface ApiInterface {

@GET("users")
Call<List<DataResponse>> getUsers(@Query("page") int page, @Query("per_page") int per_page);}

RecyclerAdapter.java

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

private List<Data> dataList;
private Context context;

public RecyclerAdapter(List<Data> dataList, Context context){

    this.dataList = dataList;
    this.context = context;
}

@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout, parent, false);
    return new MyViewHolder(view);
}

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

    Data data = dataList.get(position);
    holder.fullname.setText(data.getFirst_name() + ", " + data.getLast_name());
    Glide.with(context).load(data.getAvatar()).into(holder.avatar);
}

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

public  static class MyViewHolder extends RecyclerView.ViewHolder {

    ImageView avatar;
    TextView  fullname;

    public MyViewHolder(View itemView) {
        super(itemView);
        avatar = (ImageView) itemView.findViewById(R.id.cardView_image);
        fullname = (TextView) itemView.findViewById(R.id.cardView_location);
    }
}

public void addData(List<Data> data){

    for(Data d: data){
        dataList.add(d);
    }
}}

MainActivity

public class MainActivity extends AppCompatActivity {

private RecyclerView recyclerView;
private ProgressBar progressBar;
private GridLayoutManager layoutManager;
private RecyclerAdapter adapter;

private ApiInterface apiInterface;

private int page_num = 1;
private int per_page = 3;

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

    adapter = null;

    recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
    layoutManager = new GridLayoutManager(this, 2);
    recyclerView.setHasFixedSize(true);
    recyclerView.setLayoutManager(layoutManager);

    apiInterface = ApiClient.getApiClient().create(ApiInterface.class);

    progressBar = (ProgressBar) findViewById(R.id.progressBar);
    progressBar.setVisibility(View.VISIBLE);

    Call<List<DataResponse>> call = apiInterface.getUsers(page_num, per_page);

    call.enqueue(new Callback<List<DataResponse>>() {
        @Override
        public void onResponse(Call<List<DataResponse>> call, Response<List<DataResponse>> response) {
            Toast.makeText(MainActivity.this, "Response success....", Toast.LENGTH_SHORT).show();
            List<Data> data = response.body().get(1).getData();
            adapter = new RecyclerAdapter(data, MainActivity.this);
            recyclerView.setAdapter(adapter);
            Toast.makeText(MainActivity.this, "First page is loaded...", Toast.LENGTH_SHORT).show();
            progressBar.setVisibility(View.GONE);
        }

        @Override
        public void onFailure(Call<List<DataResponse>> call, Throwable t) {
            Toast.makeText(MainActivity.this, "Bad request", Toast.LENGTH_SHORT).show();
        }
    });
}}

Would highly appreciate any help, thank you.

Upvotes: 3

Views: 384

Answers (2)

Navneet Krishna
Navneet Krishna

Reputation: 5017

You are making an array request, convert it to object request(your api endpoint is returning json object). Change the call like this

Call<DataResponse> call = apiInterface.getUsers(page_num, per_page);

call.enqueue(new Callback<DataResponse>() {
    @Override
    public void onResponse(Call<DataResponse> call, Response<DataResponse> response) {
        Toast.makeText(MainActivity.this, "Response success....", Toast.LENGTH_SHORT).show();
        List<Data> data = response.body().getData();
        adapter = new RecyclerAdapter(data, MainActivity.this);
        recyclerView.setAdapter(adapter);
        Toast.makeText(MainActivity.this, "First page is loaded...", Toast.LENGTH_SHORT).show();
        progressBar.setVisibility(View.GONE);
    }

    @Override
    public void onFailure(Call<DataResponse> call, Throwable t) {
        Toast.makeText(MainActivity.this, "Bad request", Toast.LENGTH_SHORT).show();
    }
});

and api interface should be like this

public interface ApiInterface {
@GET("users")
Call<DataResponse> getUsers(@Query("page") int page, 
@Query("per_page") int per_page);
}

Upvotes: 1

BNG Dev
BNG Dev

Reputation: 21

Its happen because you request is failed and you are not set adapter for recycler view change it

public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;`
private ProgressBar progressBar;
private GridLayoutManager layoutManager;
private RecyclerAdapter adapter;
private ApiInterface apiInterface;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

adapter = null;

recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
layoutManager = new GridLayoutManager(this, 2);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(layoutManager);
adapter = new RecyclerAdapter(data, MainActivity.this);
        recyclerView.setAdapter(adapter);

apiInterface = ApiClient.getApiClient().create(ApiInterface.class);

progressBar = (ProgressBar) findViewById(R.id.progressBar);
progressBar.setVisibility(View.VISIBLE);

Call<List<DataResponse>> call = apiInterface.getUsers(page_num, per_page);

call.enqueue(new Callback<List<DataResponse>>() {
    @Override
    public void onResponse(Call<List<DataResponse>> call, Response<List<DataResponse>> response) {
        Toast.makeText(MainActivity.this, "Response success....", Toast.LENGTH_SHORT).show();
        List<Data> data = response.body().get(1).getData();
adapter.notifydatasetchanged()
        Toast.makeText(MainActivity.this, "First page is loaded...", Toast.LENGTH_SHORT).show();
        progressBar.setVisibility(View.GONE);
    }

    @Override
    public void onFailure(Call<List<DataResponse>> call, Throwable t) {
        Toast.makeText(MainActivity.this, "Bad request", Toast.LENGTH_SHORT).show();
    }
});
}

Upvotes: 0

Related Questions