Search code examples
javaandroidtabsandroid-lifecycleandroid-search

Android: Tabs and searchbars


I have two tabs and each tabs has its own searchbar.

I bind the searchbar in onCreateOptionsMenu. However, the searchbars only work if I leave the screen once and return to the screen (meaning it needs one more lifecycle for the searchbars to react). I confirmed that onCreateOptionsMenu is indeed called two times at the time of the creation of the ViewPagerFragment.

I bind them like this:

MenuItem searchItem = menu.findItem(R.id.search);
searchItem.setVisible(true);

SearchView searchView = (SearchView) searchItem.getActionView();
searchView.setImeOptions(EditorInfo.IME_ACTION_DONE);

searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
   @Override
    public boolean onQueryTextSubmit(String query) {
          ...
          return false;
     }

     @Override
     public boolean onQueryTextChange(String newText) {
           ...
          return false;
     }
});

I am guessing this bug is related to the tabs. How do implement a working searchbar with tabs (i.e. viewpager2)?


I call this on onCreateOptionsMenu:

public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
    super.onCreateOptionsMenu(menu, inflater);
    // Call the above...
}

The ViewPager hosting them looks like this:

private void init(View view) {
    ViewPager2 viewPager2 = view.findViewById(R.id.view_pager_fragment_view_pager);
    TabLayout tabLayout = view.findViewById(R.id.tab_layout_fragment_view_pager);
    viewPager2.setUserInputEnabled(true);

    viewPager2.setAdapter(new ViewPagerFragmentAdapter(ViewPagerFragment.this));
    viewPager2.setOffscreenPageLimit(5);

    new TabLayoutMediator
            (tabLayout, viewPager2,
                    (tab, position) -> tab.setText(titles[position])).attach();
}

Solution

  • OP and I were communicating while we found a solution.

    First each fragment was changed to

    public class MergedItemsFragment extends Fragment implements SearchView.OnQueryTextListener {
    
        /// ------------------------------
        /// SearchView.OnQueryTextListener
    
        @Override
        public boolean onQueryTextSubmit(String query) {
            // ...
            return false;
    
        }
    
        @Override
        public boolean onQueryTextChange(String newText) {
            // ...
            return false;
    
        }
    
        /// --------
        /// Fragment
    
        @Override
        public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
    
            return inflater.inflate(R.layout.fragment_merged_items, container, false);
    
        }
    
        @Override
        public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
            super.onCreateOptionsMenu(menu, inflater);
    
            final MenuItem   searchItem = menu.findItem(R.id.search);
            final SearchView searchView = (SearchView) searchItem.getActionView();
    
            searchView.setImeOptions(EditorInfo.IME_ACTION_DONE);
            searchView.setOnQueryTextListener(this);
    
        }
    
    }
    
    
    • SearchView was inflated by using a menu.xml file within the App's Activity.
    • SearchView.OnQueryTextListener was implemented by each Fragment that needed access to the SearchView
    • Since onCreateOptionsMenu() is invoked each time a Fragment is created, or subsequently comes into view (e.g. Swipe); the SearchView's OnQueryTextListener is updated to the corresponding Fragment
    • Lastly, there was a line in OP's main Fragment containing the ViewPager2, which was removed: viewPager2.setOffscreenPageLimit(5); that caused each Fragment provided by the FragmentStateAdapter to instantiate and mutate the SearchView's OnQueryTextListener each time a Fragment was created. Removing the line made sure that only the Fragment that was in view was bound to the Toolbar's SearchView.

    If any more code is desired, i'd be happy to post what I have, and if I come up with a solution using viewPager2.setOffscreenPageLimit(5); i.e. caching, i'll post that as well