Как использовать onQueryTextChange со многими фрагментами

у меня есть много фрагментов, они показаны в разделе 2 макетов с помощью FragmentStatePagerAdapter в каждом фрагменте есть представление Recycler, и я хочу использовать строку поиска в строке приложения для фильтрации результатов.

сначала я сделал это с помощью onQueryTextChange listener в onCreateOptionsMenu и он отлично работал с парой фрагментов, но когда я добавил реализацию к другим фрагментам (просто ctrl+c и ctrl+v), он перестал работать, никаких результатов даже на фрагментах, которые раньше работали, я тогда прочитал здесь что лучше вставить onQueryTextChange listener in onPrepareOptionsMenu в попытке избежать проблемы с invalidateOptionsMenu, но я решил дать эту попытку, которая также сработала, а затем, когда я добавил методы ко всем моим другим фрагментам еще раз, он терпит неудачу, но он работает на горстке фрагментов, как ни странно, все они прикреплены к одному родительскому фрагменту, но код для 4 родительских фрагментов, и для вызова их идентичен.

другой способ обойти это я прочитал creating an interface и через которое из моей основной деятельности, получив ссылку на текущий фрагмент, но затем id должен получить текущий фрагмент с моего viewpager, который я не знаю, возможно ли кто-нибудь взвесить это для меня,

большое спасибо

и спасибо за большое редактирование lol

редактировать Попробовал подход интерфейса безрезультатно, хотя я все еще новичок, мне нужно найти прикрепленный фрагмент и с помощью fragmentstateviewpager это просто невозможно без использования хаков должна быть какая-то причина, почему он работает в некоторых, а не в других, а иногда и вовсе

Изменить 2

так что я все еще возился с этим, и у меня почти не было ответов, поэтому давайте немного освежим это, поэтому я добавлял макет меню в основной деятельности, как это

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.dashboard, menu);
    SearchView searchView =  
    (SearchView)menu.findItem(R.id.action_search).getActionView();
    SearchManager searchManager = (SearchManager)  
    getSystemService(SEARCH_SERVICE);

    searchView.setSearchableInfo(searchManager
    .getSearchableInfo(getComponentName()));

    return true;
}

и затем добавление слушателя на него из фрагмента в onPrepareOptionsMenu, как это

@Override
public void onPrepareOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.       
    //in this instance we wont as it will create a duplicate

    SearchView searchView = (SearchView)
    menu.findItem(R.id.action_search).getActionView();
    searchView.setOnQueryTextListener(null);
    searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener(){
        @Override
        public boolean onQueryTextSubmit(String query) {
            return false;
        }

        @Override
        public boolean onQueryTextChange(String newText) {

            showResults(newText);

            return false;
        }

    });

    super.onPrepareOptionsMenu(menu);
}

и я назвали setHasOptionsMenu(правда) в onCreateView фрагмента, это работает отлично, но у меня около 20 осколков, чтобы перебрать и, когда я добавить это к другим фрагментам его не удается, он либо ничего не делает, или делает вид пустой или в редких случаях работает, но это для меня говорит, что мой код-это хорошо и, может быть, ее жизненный цикл вещь, я пытался позвонить из onCreateOptionsMenu отломков и достичь тех же результатов, и я старался не называть ничего из основной активности в onCreateOptions кроме раздувания меню и позволяют фрагментам вызывать поисковую активность с помощью

SearchView searchView = (SearchView)menu.findItem
(R.id.action_search).getActionView();
SearchManager searchManager = (SearchManager) 
getActivity().getSystemService(getActivity().SEARCH_SERVICE);
searchView.setSearchableInfo(searchManager.getSearchableInfo
(getActivity().getComponentName())); 

который снова работает примерно до 8 фрагментов, но мои 20 или около того просто заставляет его падать на свой меч, есть ли что-то, что я не делаю, что могло бы помочь

редактировать 3 Итак, добавив некоторые, проверив его, добавив еще несколько, проверив его, похоже, проблема с моими родительскими фрагментами, поэтому у меня есть основные фрагменты действия 4, которые каждый если я добавлю методы для прослушивателя запросов к первым 7 или около того фрагментам в первом родительском фрагменте, все они работают красиво, если я затем добавлю методы к следующему набору из 7 или около того фрагментов во втором родителе, работают только дочерние фрагменты вторых родителей, если я затем выйду из своего приложения и снова открою его, работают только фрагменты первых родителей, продолжу исследовать любую помощь скоро.

правка 4 Просто собираюсь добавить код, который я использую для родительских фрагментов и fragmentstatepager из моей основной деятельности

Итак, из моей основной деятельности я установил fragmentstatepager следующим образом

    private void setupViewPager(ViewPager viewPager) {
    ViewPagerAdapter adapter = new 
    ViewPagerAdapter(getSupportFragmentManager());
    adapter.addFrag(new sentenceMakers(), "QUICKS");
    adapter.addFrag(new tabFragOne(), "NOUNS");
    adapter.addFrag(new tabFragTwo(), "VERBS");
    adapter.addFrag(new tabFragThree(), "OBJECTS");
    viewPager.setAdapter(adapter);

}

class ViewPagerAdapter extends FragmentStatePagerAdapter {
    private final List<Fragment> mFragmentList = new ArrayList<>();
    private final List<String> mFragmentTitleList = new ArrayList<>();

    public ViewPagerAdapter(FragmentManager manager) {
        super(manager);
    }

    @Override
    public Fragment getItem(int position) {
        return mFragmentList.get(position);
    }

    @Override
    public void restoreState(Parcelable arg0, ClassLoader arg1) {
        //do nothing here! no call to super.restoreState(arg0, arg1);
    }
    @Override
    public int getCount() {
        return mFragmentList.size();
    }

    public void addFrag(Fragment fragment, String title) {
        mFragmentList.add(fragment);
        mFragmentTitleList.add(title);
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return mFragmentTitleList.get(position);
    }
}

и мои родительские фрагменты выглядят так

public class sentenceMakers extends Fragment{

public ImageView imageView;
private ViewPager viewPager;
public static TabLayout tabLayout;

public sentenceMakers() {
    // Required empty public constructor
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState){
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View rootView = inflater.inflate
    (R.layout.tab_frag_one, container, false);
    // Inflate the layout for this fragment
    //setRetainInstance(true);
    viewPager = (ViewPager) rootView.findViewById(R.id.viewpager);
    setupViewPager(viewPager);
    tabLayout = (TabLayout) rootView.findViewById(R.id.tabs);
    tabLayout.setupWithViewPager(viewPager);
    setupTabIcons();

    return rootView;

}
@Override
public void onActivityCreated(Bundle savedInstanceState){
    super.onActivityCreated(savedInstanceState);

}

private void setupTabIcons() {
    TextView tabZero2 = (TextView) 
    LayoutInflater.from(getActivity()).inflate(R.layout.custom_tab, null);
    tabZero2.setText("FAVOURITES");
    //tabOne.setGravity(View.TEXT_ALIGNMENT_CENTER);
    tabZero2.setCompoundDrawablesWithIntrinsicBounds(0, 
    R.drawable.ic_star_white_24dp, 0, 0);
    tabLayout.getTabAt(0).setCustomView(tabZero2);

    TextView tabZero = (TextView) 
    LayoutInflater.from(getActivity()).inflate(R.layout.custom_tab, null);
    tabZero.setText("FREQUENTS");
    //tabOne.setGravity(View.TEXT_ALIGNMENT_CENTER);
    tabZero.setCompoundDrawablesWithIntrinsicBounds(0, 
    R.drawable.ic_people_outline_white_24dp, 0, 0);
    tabLayout.getTabAt(1).setCustomView(tabZero);

    TextView tabOne = (TextView) 
    LayoutInflater.from(getActivity()).inflate(R.layout.custom_tab, null);
    tabOne.setText("PRONOUNS");
    //tabOne.setGravity(View.TEXT_ALIGNMENT_CENTER);
    tabOne.setCompoundDrawablesWithIntrinsicBounds(0, 
    R.drawable.ic_accessibility_white_24dp, 0, 0);
    tabLayout.getTabAt(2).setCustomView(tabOne);

    TextView tabTwo = (TextView) 
    LayoutInflater.from(getActivity()).inflate(R.layout.custom_tab, null);
    tabTwo.setText("CONJUCTIONS");
    tabTwo.setCompoundDrawablesWithIntrinsicBounds(0, 
    R.drawable.ic_add_white_24dp, 0, 0);
    tabLayout.getTabAt(3).setCustomView(tabTwo);

    TextView tabThree = (TextView) 
    LayoutInflater.from(getActivity()).inflate(R.layout.custom_tab, null);
    tabThree.setText("ADJECTIVES");
    tabThree.setCompoundDrawablesWithIntrinsicBounds(0, 
    R.drawable.ic_favorite_border_white_24dp, 0, 0);
    tabLayout.getTabAt(4).setCustomView(tabThree);

    tabLayout.getTabAt(0).getCustomView().setSelected(true);
}

private void setupViewPager(ViewPager viewPager) {
    ViewPagerAdapter adapter = new 
    ViewPagerAdapter(getChildFragmentManager());
    adapter.addFrag(new favouriteCards(), "FAVOURITES");
    adapter.addFrag(new predictedCards(), "FREQUENTS");
    adapter.addFrag(new pronouns(), "PRONOUNS");
    adapter.addFrag(new conjuctions(), "CONJUNCTIONS");
    adapter.addFrag(new Others(), "ADJECTIVES");
    viewPager.setAdapter(adapter);
}

class ViewPagerAdapter extends FragmentPagerAdapter {
    private final List<Fragment> mFragmentList = new ArrayList<>();
    private final List<String> mFragmentTitleList = new ArrayList<>();

    public ViewPagerAdapter(FragmentManager manager) {
        super(manager);
    }

    @Override
    public Fragment getItem(int position) {
        return mFragmentList.get(position);
    }

    @Override
    public int getCount() {
        return mFragmentList.size();
    }

    public void addFrag(Fragment fragment, String title) {
        mFragmentList.add(fragment);
        mFragmentTitleList.add(title);
    }
}
}

все еще борется с этим, и я не могу для жизни меня понять, почему он будет работать в одной партии фрагментов, пока я не добавлю его в следующий набор, его то же самое с тем же кодом, он должен просто инициализировать последние фрагменты, которые просят его, может ли кто-нибудь помочь мне здесь? Спасибо за любую помощь

3 ответов


в принципе, есть вещь, которую вы должны иметь в виду, когда используете фрагменты: Не держите ссылки на ваши фрагменты: просто создайте их и добавьте в свой макет или предоставьте вашему ViewPager, но затем используйте другие методы для их извлечения, например FragmentManager.findFragmentBy...

тем не менее, ваш код должен быть (позвольте мне упростить всего два фрагмента):

Главная активность

private void setupViewPager(ViewPager viewPager) {
    ViewPagerAdapter adapter = new MyViewPagerAdapter(getSupportFragmentManager());
    viewPager.setAdapter(adapter);
}

class MyViewPagerAdapter extends FragmentStatePagerAdapter {

    public ViewPagerAdapter(FragmentManager manager) {
        super(manager);
    }

    @Override
    public Fragment getItem(int position) {
        switch(position) {
            case 0:
                return new sentenceMakers();
            case 1:
                return new tabFragOne();
            // add here fragments for any other position
        }
    }

    @Override
    public int getCount() {
        return 2;
    }

    @Override
    public CharSequence getPageTitle(int position) {
        switch(position) {
            case 0:
                return "QUICKS";
            case 1:
                return "NOUNS";
            // add here titles for any other position
        }
    }
}

sentenceMakers

код, который вам придется использовать в вашем фрагменте sentenceMakers, очень похож на предыдущий, но вам придется использовать дочерний fragmentManager (как и в вашем коде), и снова не держите свои фрагменты в списке, пусть система создает их при необходимости.


ок, я исправил это так проблема в том, что родитель fragmentstatepager нагрузок fragmentA + fragmentB в памяти, тогда ребенок fragmentstatepagers нагрузки там своя childfragmentA + childfragmentB так что теперь у нас 2 родителей и 4 детей, onPrepareOptionsMenu называется с детьми фрагменты, так что первым загружается childfragmentA(ребенок fragmentA), а затем childFragmentA(ребенок fragmentB) загружается и ворует поиска просмотреть, мой "исправить" это, наверное, немного сырой я себя учил, и я не очень знаю, как управлять памятью или если ее плохо держать ссылки и т. д., я отвлекаюсь, в Родительском фрагменте я проверяю, какой фрагмент виден с помощью

setMenuVisibility(final boolean visible)

и там я установил публичное статическое логическое значение и проверил его в своих childfragments, и он работает безупречно для меня, как упоминалось, это, вероятно, ужасная вещь, чтобы сделать, надеюсь, кто-то здесь может дать лучшее решение

проверьте, какой родитель видимый

public static boolean tabFragOneVisible;

@Override
public void setUserVisibleHint(boolean isVisible){
    super.setUserVisibleHint(isVisible);
    if(!isVisible){
        tabFragOneVisible = false;
    }else{
        tabFragOneVisible = true;
    }
}

проверьте, если родитель виден подключить вид поиска

@Override
public void onPrepareOptionsMenu(Menu menu) {
    // need to check if fragment is visible
    if (tabFragOne.tabFragOneVisible) {
        SearchView searchView = (SearchView)
        menu.findItem(R.id.action_search).getActionView();
        SearchManager searchManager = (SearchManager) getActivity()
        .getSystemService(getActivity().SEARCH_SERVICE);
        searchView.setSearchableInfo(searchManager
        .getSearchableInfo(getActivity().getComponentName()));
        // searchView.setOnQueryTextListener(null);
        searchView.setOnQueryTextListener(new  
        SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                return false;
            }

            @Override
            public boolean onQueryTextChange(String newText) {

                showResults(newText);
                return false;
            }

        });
    }
    else{

    }
    super.onPrepareOptionsMenu(menu);
}

возможно, это все равно поможет кому-то изо всех сил заставить один SearchView работать для нескольких фрагментов. Я обнаружил, что onQueryTextListener будет работать на фрагменте 1 (где изначально создается SearchView), но не будет работать на фрагменте 2,3 и т. д.

фрагменты 2 работали, когда onPrepareOptionsMenu переопределяется и onViewCreated включает setHasOptionsMenu(true). Например:

@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    setHasOptionsMenu(true);
        ...the rest of your code goes here...
}
@Override
public void onPrepareOptionsMenu(Menu menu) {
    MenuItem item = menu.findItem(R.id.action_search);
    SearchView searchView = (SearchView) item.getActionView();
    searchView.setOnQueryTextListener(this);
    super.onPrepareOptionsMenu(menu);
}


@Override
public boolean onQueryTextSubmit(String query) {
    return false;
}
@Override
public boolean onQueryTextChange(String newText) {
    Toast.makeText(getActivity(),"It Worked!!",Toast.LENGTH_SHORT).show();
    return true;
}