Onur Çevik
Onur Çevik

Reputation: 1590

RecyclerView not populated until SearchView interaction

I'm facing an issue with my recyclerview, which has a custom adapter. Issue is that when the activity opens, recyclerview is empty. When user types anything on SearchView's text field, recyclerview gets populated and stays populated without any problems. I tried to change place of some code to fix this issue, yet no success. I've added the current and desired state screenshots below the codes. Thanks in advance.

AddCourseActivity:

public class AddCourseActivity extends AppCompatActivity{

private RecyclerView mRecyclerView;
private AddCourseAdapter mAdapter;
private List<AddCourseAdapter.AddCourseModel> mModels;
SearchView mSearchView;

@Override
protected void onCreate(Bundle savedInstance) {
    super.onCreate(savedInstance);
    setContentView(R.layout.activity_add_course);
    Kii.initialize(AppConstants.APP_ID, AppConstants.APP_KEY,
            AppConstants.APP_SITE);
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    getSupportActionBar().setDisplayShowHomeEnabled(true);
    mRecyclerView = (RecyclerView) findViewById(R.id.addcourseRecyclerView);
    mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
    String[] courses = new String[]{
            "Math119",
            "Enve101",
            "Chem107",
            "Chem229",
            "Phys105",
            "Math120"};
    mModels = new ArrayList<>();
    mAdapter = new AddCourseAdapter(this, mModels);
    mSearchView = (SearchView) findViewById(R.id.searchView);
    mSearchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
        @Override
        public boolean onQueryTextSubmit(String query) {
            return false;
        }
        @Override
        public boolean onQueryTextChange(String newText) {
            final List<AddCourseAdapter.AddCourseModel> filteredModelList = filter(mModels, newText);
            mAdapter.animateTo(filteredModelList);
            mRecyclerView.scrollToPosition(0);
            return true;
        }
    });
    for (String course: courses) {
        mModels.add(new AddCourseAdapter.AddCourseModel(course));
        mRecyclerView.setAdapter(mAdapter);
        mAdapter.notifyDataSetChanged();
    }
}

private List<AddCourseAdapter.AddCourseModel> filter(List<AddCourseAdapter.AddCourseModel> models, String query) {
    query = query.toLowerCase();
    final List<AddCourseAdapter.AddCourseModel> filteredModelList = new ArrayList<>();
    for (AddCourseAdapter.AddCourseModel model: models) {
        final String text = model.getText().toLowerCase();
        if (text.contains(query)) {
            filteredModelList.add(model);
        }
    }
    return filteredModelList;
}
}

AddCourseAdapter:

public class AddCourseAdapter extends RecyclerView.Adapter<AddCourseAdapter.AddCourseViewHolder> {
private final LayoutInflater mInflater;
private final List<AddCourseModel> mModels;
KiiUser user;
KiiObject object;
KiiBucket userBucket;
Context context;

public AddCourseAdapter(Context context, List<AddCourseModel> models) {
    mInflater = LayoutInflater.from(context);
    mModels = new ArrayList<>(models);
}

@Override
public AddCourseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    context = parent.getContext();
    final View itemView = mInflater.inflate(R.layout.list_item_add_course, parent, false);
    user = KiiUser.getCurrentUser();
    final String username = user.getUsername();
    userBucket = Kii.user().bucket(username);
    String id = "mycourses";
    object = userBucket.object(id);
    return new AddCourseViewHolder(itemView);
}

@Override
public void onBindViewHolder(final AddCourseViewHolder holder, int position) {
    final AddCourseModel model = mModels.get(position);
    holder.bind(model);
    holder.addButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            final String value = holder.mTextView.getText().toString();
            object.refresh(new KiiObjectCallBack() {
                @Override
                public void onRefreshCompleted(int token, @NonNull KiiObject object, Exception exception) {
                    object.set(value, true);
                    object.saveAllFields(new KiiObjectCallBack() {
                        @Override
                        public void onSaveCompleted(int token, KiiObject object, Exception exception) {
                            Toast.makeText(context,
                                    "Added: " + value,
                                    Toast.LENGTH_SHORT)
                                    .show();
                        }
                    }, false);
                }
            });
            holder.addButton.setVisibility(View.GONE);
            holder.removeButton.setVisibility(View.VISIBLE);
        }
    });
    holder.removeButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(final View v) {
            final String value = holder.mTextView.getText().toString();
            object.refresh(new KiiObjectCallBack() {
                @Override
                public void onRefreshCompleted(int token, @NonNull KiiObject object, Exception exception) {
                    object.set(value, false);
                    object.saveAllFields(new KiiObjectCallBack() {
                        @Override
                        public void onSaveCompleted(int token, @NonNull KiiObject object, Exception exception) {
                            Toast.makeText(context,
                                    "Removed: " + value,
                                    Toast.LENGTH_SHORT)
                                    .show();
                        }
                    }, false);
                }
            });

            holder.addButton.setVisibility(View.VISIBLE);
            holder.removeButton.setVisibility(View.GONE);
        }
    });
}

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

public void animateTo(List<AddCourseModel> models) {
    applyAndAnimateRemovals(models);
    applyAndAnimateAdditions(models);
    applyAndAnimateMovedItems(models);
}

private void applyAndAnimateRemovals(List<AddCourseModel> newModels) {
    for (int i = mModels.size() - 1; i >= 0; i--) {
        final AddCourseModel model = mModels.get(i);
        if (!newModels.contains(model)) {
            removeItem(i);
        }
    }
}

private void applyAndAnimateAdditions(List<AddCourseModel> newModels) {
    for (int i = 0, count = newModels.size(); i < count; i++) {
        final AddCourseModel model = newModels.get(i);
        if (!mModels.contains(model)) {
            addItem(i, model);
        }
    }
}

private void applyAndAnimateMovedItems(List<AddCourseModel> newModels) {
    for (int toPosition = newModels.size() - 1; toPosition >= 0; toPosition--) {
        final AddCourseModel model = newModels.get(toPosition);
        final int fromPosition = mModels.indexOf(model);
        if (fromPosition >= 0 && fromPosition != toPosition) {
            moveItem(fromPosition, toPosition);
        }
    }
}

public AddCourseModel removeItem(int position) {
    final AddCourseModel model = mModels.remove(position);
    notifyItemRemoved(position);
    return model;
}

public void addItem(int position, AddCourseModel model) {
    mModels.add(position, model);
    notifyItemInserted(position);
}

public void moveItem(int fromPosition, int toPosition) {
    final AddCourseModel model = mModels.remove(fromPosition);
    mModels.add(toPosition, model);
    notifyItemMoved(fromPosition, toPosition);
}

public class AddCourseViewHolder extends RecyclerView.ViewHolder {
    private final TextView mTextView;
    private final ImageButton addButton;
    private final ImageButton removeButton;

    public AddCourseViewHolder(View itemView) {
        super(itemView);
        mTextView = (TextView) itemView.findViewById(R.id.addCourseTV);
        addButton = (ImageButton) itemView.findViewById(R.id.addButton);
        removeButton = (ImageButton) itemView.findViewById(R.id.removeButton);
    }

    public void bind(AddCourseModel model) {
        mTextView.setText(model.getText());
    }
}

public static class AddCourseModel {
   private final String mText;

   public AddCourseModel(String text) {
       this.mText = text;
   }

   public String getText() {
       return mText;
   }
}
}

Current Initial State:

Desired Initial State:

Upvotes: 0

Views: 247

Answers (1)

aelimill
aelimill

Reputation: 1015

The case is in your Adapter constructor

public AddCourseAdapter(Context context, List<AddCourseModel> models) {
    mInflater = LayoutInflater.from(context);
    mModels = new ArrayList<>(models);
}

You create new ArrayList which initially populated from the models list (which is empty at this moment). Later you populate initial models arraylist, not the one created in adapter.

You can:

a) move the

for (String course: courses) {
        mModels.add(new AddCourseAdapter.AddCourseModel(course));
        mRecyclerView.setAdapter(mAdapter);
        mAdapter.notifyDataSetChanged();
    }

between those lines

mModels = new ArrayList<>();
mAdapter = new AddCourseAdapter(this, mModels);

making in looking like this

mModels = new ArrayList<>();

for (String course: courses) {
  mModels.add(new AddCourseAdapter.AddCourseModel(course));
}
mAdapter = new AddCourseAdapter(this, mModels);
mRecyclerView.setAdapter(mAdapter);

OR

b) rewrite the Adapter constructor to

public AddCourseAdapter(Context context, List<AddCourseModel> models) {
        mInflater = LayoutInflater.from(context);
        mModels = models;
    }

Upvotes: 1

Related Questions