0

I have a simple program that connect to an API and get some data from it.I use Retrofit library.There are two activity. MainActivity includes a RecyclerView that show data received from the server. If press any item,application go to UserInfoActivity and show detailed information of that item.My app when go UserInfoActivity crashed after a few seconds and don't show information. However response correctly received but the program gives an error on txtId.setText(user.getId) line. The error is E/RecyclerView: No adapter attached; skipping layout In fact my problem starts when call Call<User> getUserInfo(@Path("id") int id); in second Activity.

This is MainActivity code.

 protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    userRequest();
}

private void userRequest(){
    APIInterface apiInterface= APIClient.getClient().create(APIInterface.class);
    retrofit2.Call<ArrayList<User>> call= apiInterface.getUsers();
    call.enqueue(new Callback<ArrayList<User>>() {
        @Override
        public void onResponse(retrofit2.Call<ArrayList<User>> call, Response<ArrayList<User>> response) {
            if(response.isSuccessful()){
                ArrayList<User> users = response.body();
                setupRecycelerView(users);
            }
        }
        @Override
        public void onFailure(retrofit2.Call<ArrayList<User>> call, Throwable t) {
            Log.i("RETROFIT","response not successful");
        }
    });
}

private void setupRecycelerView(ArrayList<User> users){
    recyclerView=findViewById(R.id.RcyView);
    adapter=new RecycelerAdapter(this,users);
    linearLayoutManager=new LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false);
    recyclerView.setAdapter(adapter);
    recyclerView.setHasFixedSize(true);
    recyclerView.setLayoutManager(linearLayoutManager);
    recyclerView.setItemAnimator(new DefaultItemAnimator());

}

This is onBindViewHolder function of RecycelerAdapter.

 public void onBindViewHolder(@NonNull UserViewHolder holder, int position) {
    final User user=values.get(position);
    holder.txtName.setText(user.getName());
    holder.txtPhone.setText(user.getPhone());
    final Intent intent=new Intent(context, UserInfoActivity.class);
    intent.putExtra("user",user);
    holder.root.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            context.startActivity(intent);
        }
    });
}

This is UserInfoActivity code.

 protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_user_info);
    txtId=findViewById(R.id.txtId);
    txtName=findViewById(R.id.txtName);
    txtPhone=findViewById(R.id.txtPhone);
    Intent intent=getIntent();
    User user=(User)intent.getSerializableExtra("user");
    id=user.getId();
    userInfoRequest();
}
private void userInfoRequest(){
    APIInterface apiInterface= APIClient.getClient().create(APIInterface.class);
    retrofit2.Call<User> call= apiInterface.getUserInfo(id);
    call.enqueue(new Callback<User>() {
        @Override
        public void onResponse(Call<User> call, Response<User> response) {
            if(response.isSuccessful()){
                User user=response.body();
                Log.e("MF","ON Response");
                Log.e("MF",user.getName());
                Log.e("MF",user.getPhone());
                txtId.setText(user.getId());
                txtName.setText(user.getName());
                txtPhone.setText(user.getPhone());
            }
        }
        @Override
        public void onFailure(Call<User> call, Throwable t) {
            Log.e("MF","on failure");
        }
    });

}
maryam
  • 1,437
  • 2
  • 18
  • 40

4 Answers4

1

Try this:

linearLayoutManager=new LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false);
recyclerView.setLayoutManager(linearLayoutManager);
adapter=new RecycelerAdapter(this,users);
recyclerView.setAdapter(adapter);
adapter.notifyDataSetChanged();
recyclerView.setHasFixedSize(true);
recyclerView.setItemAnimator(new DefaultItemAnimator());

Used notifyDataSetChanged() to tell the RecyclerView that data changed-added and set the Adapter after setLayoutManager.


If this didn't help, initialize the RecyclerView inside onCreate method and set the Adapter in onResponse with runOnUiThread like following:

runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                    //Do something on UiThread
                   ArrayList<User> users = response.body();
                   adapter=new RecycelerAdapter(this,users);
                   recyclerView.setAdapter(users);
                }
            });

Then call notifyDataSetChanged() and it should work then.

ʍѳђઽ૯ท
  • 16,646
  • 7
  • 53
  • 108
  • I do every four answers but my problem don't solve yet! – maryam Sep 14 '18 at 08:03
  • So, initialize the `RecyclerView` inside `onCreate` method and set the `Adapter` in `onResponse` after `ArrayList users = response.body();` with `runOnUiThread`. It would work then. I have updated the answer. – ʍѳђઽ૯ท Sep 14 '18 at 08:06
  • Unfortunately, the same error repeats. – maryam Sep 14 '18 at 08:22
  • `E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.np.retrofitarcademy, PID: 14983 android.content.res.Resources$NotFoundException: String resource ID #0x4 at android.content.res.Resources.getText(Resources.java:1468) at android.widget.TextView.setText(TextView.java:5051) at com.example.np.retrofitarcademy.UserInfoActivity$1.onResponse(UserInfoActivity.java:50)` – maryam Sep 14 '18 at 08:24
  • Oh, that’s another issue actually, would you add the logcat in your question and I’d vote to open the question? Please edit the title and content with the following logs. Issue comes from SetText gettext in your model i suppose. We might need to check that too – ʍѳђઽ૯ท Sep 14 '18 at 08:25
  • I still have the previous error. `No adapter attached; skipping layout` – maryam Sep 14 '18 at 08:29
  • That’s just a warning, issue seems to be the model.. **NotFoundException: String resource ID** – ʍѳђઽ૯ท Sep 14 '18 at 08:30
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/180040/discussion-between-sarina-and-w). – maryam Sep 14 '18 at 08:45
1

You're calling the setupRecycelerView on the response of the Retrofit api call, the problem is that till the response comes the RecyclerView doesnt have an adapter or a layoutManager attached to itself, hence the error.

Instead, you can call the setupRecycelerView inside onCreate itself and then create a global object of the Users list. Something like this:

private final ArrayList<Users> users = new ArrayList();

This list would be empty and the adapter would be initialised with the same empty list, then when you get the response from the retrofit api, use:

users.addAll(response.getBody());

this will fill the contents and then call adapter.notifyDataSetChanged(); to make the adapter reflect the updated contents.

MadScientist
  • 2,134
  • 14
  • 27
1

This happens because you initialize RecyclerView when/if the response from server is successful.

Initialize it (call setupRecycelerView() ) in onCreate(). And change adapter=new RecycelerAdapter(this,users); to adapter=new RecycelerAdapter(this);

Make your RecycelerAdapter's constructor take one argument only (probably Context) In your adapter, make a public method that sets the users.

public setUserData(ArrayList<User> users) {
    this.values = users;
    notifyDataSetChanged();
}

Call RecycelerAdapter.setUserData(users); from Retrofit's response is successful.

ashazar
  • 714
  • 5
  • 11
1

Just call setAdapter() after setLayoutManager() in your setupRecycelerView()

prashant17
  • 1,520
  • 3
  • 14
  • 23