0

I am currently very stuck on a simple problem with a RecyclerView Adapter. The adapter takes a list of custom objects and displays them, which works as intended. But when I want to filter the list via a searchbar and apply the changes via adapter.notifyDataSetChanged, nothing happens.

I know this question has already been asked multiple times, but I tried all the advice in these posts and could not find an answer that works for me. So here is my structure:

  1. I use my Activity to inflate a TabLayout with three tabs
  2. I then use a seperate Class to get my data and parse it into three lists.
  3. Afterwards, a Fragment adapter to connects a Fragment to each of the tabs.
  4. The Fragments are supposed to fetch the lists, apply my RecyclerView Layout and set the Layout Manager.
  5. Each list has an Adapter which then inflates the entries and applies an onClickListener.

Now everything works here, and I can successfully filter my lists, I simply cannot apply the changed lists to the adapter(s).

Activity:


public class OrganizerActivity extends AppCompatActivity {
    ListView listView;
    ViewPager2 viewPager;
    OrganizerFragmentAdapter organizerFragmentAdapter;
    MaterialToolbar toolbar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.organizer_layout);
        toolbar = findViewById(R.id.topAppBar);
        setSupportActionBar(toolbar);
        NavigationUtilities.setUpNavigation(this, R.id.organizer);
        createView();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.organizer_top_app_bar, menu);

        SearchManager searchManager =
                (SearchManager) getSystemService(Context.SEARCH_SERVICE);
        SearchView searchView =
                (SearchView) menu.findItem(R.id.organizerSearchIcon).getActionView();
        searchView.setSearchableInfo(
                searchManager.getSearchableInfo(getComponentName()));
        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                return false;
            }

            @Override
            public boolean onQueryTextChange(String newText) {
                System.out.println(newText);
                organizerFragmentAdapter.setQuery(newText);
                return false;
            }
        });
       return super.onCreateOptionsMenu(menu);
    }

    public void createView() {
        TabLayout tabLayout = findViewById(R.id.organizerTabLayout);
        viewPager = findViewById(R.id.organizerViewPager);
        listView = findViewById(R.id.org_recylclerview);
        organizerFragmentAdapter = new OrganizerFragmentAdapter(this);
        viewPager.setAdapter(organizerFragmentAdapter);
        viewPager.setOffscreenPageLimit(2);

        TabLayoutMediator tabLayoutMediator = new TabLayoutMediator(tabLayout, viewPager, (tab, position) -> {
            switch (position){
                case 0:
                    tab.setText("Courses");
                    break;
                case 1:
                    tab.setText("People");
                    break;
                case 2:
                    tab.setText("Rooms");
                    break;
                default:
                    break;
            }
        });
        tabLayoutMediator.attach();

    }

    @Override
    public void onBackPressed(){
        if (viewPager.getCurrentItem() == 0) {
            // If the user is currently looking at the first step, allow the system to handle the
            // Back button. This calls finish() on this activity and pops the back stack.
            super.onBackPressed();
        } else {
            // Otherwise, select the previous step.
            viewPager.setCurrentItem(viewPager.getCurrentItem() - 1);
        }
    }

}


Fragment:

public class OrganizerOverallFragment extends Fragment{

    int position;
    String currentQuery;
    RecyclerView recyclerView;
    ArrayList<Course> courses;
    ArrayList<Person> people;
    ArrayList<Room> rooms;
    View view;
    OrganizerCourseAdapter courseAdapter;

    CourseDataHandler courseDataHandler;



    public OrganizerOverallFragment(int position, String currentQuery) {
        this.position = position;
        this.currentQuery = currentQuery;
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        parseThread.start();
    }

    @Override
    public void onViewCreated(@NonNull View v, @Nullable Bundle savedInstanceState) {
        LayoutInflater inflater  = getLayoutInflater();
        super.onViewCreated(view,savedInstanceState);
        setHasOptionsMenu(true);
        recyclerView = view.findViewById(R.id.org_recylclerview);
        recyclerView.setLayoutManager(new LinearLayoutManager(this.getContext()));

        try {
            parseThread.join();
            courseAdapter = new OrganizerCourseAdapter(courses);
            OrganizerPersonAdapter personAdapter = new OrganizerPersonAdapter(this.getContext(),people);
            OrganizerRoomAdapter roomAdapter = new OrganizerRoomAdapter(this.getContext(),rooms);
            switch(position) {
                case 0:
                    recyclerView.setAdapter(courseAdapter);
                    break;
//                case 1:
//                    listView.setAdapter(personAdapter);
//                    personAdapter.addAll(people);
//                    break;
//                case 2:
//                    listView.setAdapter(roomAdapter);
//                    roomAdapter.addAll(rooms);
//                    break;
                default:
                    break;
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        view = inflater.inflate(R.layout.organizertab,container,false);
        return view;
    }

    Thread parseThread = new Thread(new Runnable() {
        @Override
        public void run() {
            OrganizerParser organizerParser = new OrganizerParser();
            Map<String, ArrayList> entryMap = organizerParser.getAllElements();
            courses = entryMap.get("courses");
            courseDataHandler = new CourseDataHandler(courses);
            people = entryMap.get("people");
            rooms = entryMap.get("rooms");
        }});

    public void setQuery(String query){
        currentQuery = query;
        courses = courseDataHandler.filter(query);
        System.out.println("Query: " + query +" \n " + courses);
        courseAdapter.notifyDataSetChanged();

    }
}

Adapter:

public class OrganizerCourseAdapter extends RecyclerView.Adapter<OrganizerCourseAdapter.ViewHolder>{
    ArrayList<Course> courses;
    ArrayList<Course> filteredData;

    public OrganizerCourseAdapter(ArrayList<Course> courses) {
        this.courses = courses;
        filteredData = new ArrayList<>(courses);
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        // below line is to inflate our layout.
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.organizer_entry, parent, false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull OrganizerCourseAdapter.ViewHolder holder, int position) {
        // setting data to our views of recycler view.
        Course course = courses.get(position);
        holder.tvName.setText(course.getName());
        holder.tvHome.setText(course.getStudy());
        // Return the completed view to render on screen
        setOnClickListener(holder.itemView,course);
    }

    @Override
    public int getItemCount() {
        // returning the size of array list.
        return filteredData.size();
    }

    public Object getItem(int position) {
        return filteredData.get(position);
    }

    public long getItemId(int position) {
        return position;
    }

    public void setOnClickListener(View newRow, Course course){
        newRow.setOnClickListener(new View.OnClickListener() {
            @SuppressLint("SetTextI18n")
            @Override
            public void onClick(View v) {
                BottomSheetDialog bottomSheetDialog = new BottomSheetDialog(newRow.getContext());

                bottomSheetDialog.setContentView(R.layout.organizercoursebottomsheet);
                bottomSheetDialog.show();

                try {
                    TextView entryView = bottomSheetDialog.findViewById(R.id.organizerCourseEntryText);
                    Objects.requireNonNull(entryView).setText(course.name);
                    TextView studyView = bottomSheetDialog.findViewById(R.id.organizerCourseStudyText);
                    Objects.requireNonNull(studyView).setText("Study: " + course.study);
                    TextView yearView = bottomSheetDialog.findViewById(R.id.organizerCourseYearText);
                    Objects.requireNonNull(yearView).setText("Year: " + course.year);
                    TextView roomView = bottomSheetDialog.findViewById(R.id.organizerCourseRoomText);
                    if(course.roomNo != null && roomView != null) {
                        (roomView).setText("Room: " + course.roomNo);
                    }
                    else{
                        assert roomView != null;
                        (roomView).setVisibility(View.GONE);
                    }
                    TextView urlText = bottomSheetDialog.findViewById(R.id.organizerCourseUrlText);
                    if(course.url != null && urlText != null) {
                        (urlText).setText("URL: " + Html.fromHtml(course.url,0));
                        urlText.setMovementMethod(LinkMovementMethod.getInstance());
                    }
                    else{
                        (roomView).setVisibility(View.GONE);
                    }


                    bottomSheetDialog.show();
                }
                catch (Exception e){
                    e.printStackTrace();
                }
            }
        });
    }

    public class ViewHolder extends RecyclerView.ViewHolder {
        // creating variables for our views.
        private final TextView tvName;
        private final TextView tvHome;
        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            // initializing our views with their ids.
            tvName = itemView.findViewById(R.id.info_box1);
            tvHome = itemView.findViewById(R.id.info_box2);

        }
    }
}

PS: I also looked at my Layout and removed the LinearLayout, as stated in another post.

Edit: I now have found out that the RecyclerView only updates once I scroll down and scroll back up. I still have no clue why that is.

Edit2: Thank you all for answering, I have figured it out now. Because I used a TabLayout which initialized three instances of my Fragment, the references were skewed. I had to seperate the three Fragments in my FragmentAdapter and set the query to each one and now it works! Some more code here:

Fragment-Adapter:


public class OrganizerFragmentAdapter extends FragmentStateAdapter {
    String currentQuery = "";
    OrganizerOverallFragment courseFragment;
    OrganizerOverallFragment personFragment;
    OrganizerOverallFragment roomFragment;
    int position;

    public OrganizerFragmentAdapter(@NonNull FragmentActivity fragmentActivity) {
        super(fragmentActivity);
    }

    @NonNull
    @Override
    public Fragment createFragment(int position) {
        this.position = position;
        switch (position){
            case 0:
                courseFragment = new OrganizerOverallFragment(position,currentQuery);
                return courseFragment;
            case 1:
                personFragment = new OrganizerOverallFragment(position, currentQuery);
                return personFragment;
            case 2:
                roomFragment = new OrganizerOverallFragment(position, currentQuery);
                return roomFragment;
            default:
                return createFragment(0);
        }
    }


    @Override
    public int getItemCount() {
        return 3;
    }

    public void setQuery(String query){
        currentQuery = query;

        courseFragment.setQuery(query);
        personFragment.setQuery(query);
        roomFragment.setQuery(query);
    }
}

New setQuery method:


public void setQuery(String query){
        currentQuery = query;

        switch(position) {
            case 0:
                courses.clear();
                courses.addAll(courseDataHandler.filter(query));
                courseAdapter.notifyDataSetChanged();
                break;
            case 1:
                people.clear();
                people.addAll(personDataHandler.filter(query));
                personAdapter.notifyDataSetChanged();
                break;
            case 2:
                rooms.clear();
                rooms.addAll(roomsDataHandler.filter(query));
                roomAdapter.notifyDataSetChanged();
                break;
            default:
                break;
        }
    }

1 Answers1

2

You have to make a separate function inside your Adapter to replace existing list with the new filtered list.

public void setFilteredList(ArrayList<Course> courses) {
    this.courses = courses;
    notifyDataSetChanged();
}

Now instead of calling courseAdapter.notifyDataSetChanged();inside your setQuery() function, you can call courseAdapter.setFilteredList(courses)

Sambhav Khandelwal
  • 3,585
  • 2
  • 7
  • 38
Abu bakar
  • 751
  • 1
  • 4
  • 16
  • Thanks for the answer. Unfortunately I already tried that, and it did not work. The new courses are set within the adapter, but it still won't update the list. – InFumumVerti May 18 '22 at 10:39
  • @InFumumVerti I think you are trying to update your recyclerView after just adding new courses on your `Server`. If it is true then it is not possible to direct update recyclerView on Updating server. You need to add any`RefreshListner` or `RefreshLayout` to refresh the layout. Then you can refresh your layout. – M DEV May 18 '22 at 12:44