简体   繁体   中英

RecyclerView Adapter not able to update

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;
        }
    }

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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM