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:
Activity
to inflate a TabLayout
with three tabsClass
to get my data and parse it into three lists.Fragment adapter
to connects a Fragment
to each of the tabs.Fragments
are supposed to fetch the lists, apply my RecyclerView
Layout and set the Layout Manager
. 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.