如何将 onQueryTextChange 与许多片段一起使用

How to use onQueryTextChange with many fragments

我有很多片段,它们显示在 2 个选项卡布局中,使用 FragmentStatePagerAdapter 在每个片段中都有一个 Recycler 视图,我想使用应用栏中的搜索栏来过滤结果。

首先,我使用 onCreateOptionsMenu 中的 onQueryTextChange listener 完成了此操作,并且它可以很好地处理几个片段,但是当我将实现添加到其他片段(仅 ctrl+c 和 ctrl+v)时,它停止工作,即使在曾经有效的片段上也没有结果然后我读到 最好坚持 onQueryTextChange listener in onPrepareOptionsMenu 以避免 invalidateOptionsMenu 出现问题但我决定尝试一下也有效然后当我将这些方法添加到我的所有其他片段时再次失败但它确实适用于少数片段,奇怪的是这些恰好都附加到同一个 parent 片段但是 4 [= 的代码73=] 个片段,并且调用它们是相同的。

我读过的另一种解决方法是 creating an interface 并通过获取对当前片段的引用来从我的主要 activity 使用它,但随后 id 必须从中获取当前显示的片段我不知道我的 viewpager 是否可行 任何人都可以为我权衡一下,

非常感谢

感谢您的精彩编辑,哈哈

编辑 尝试接口方法无济于事,虽然我仍然是初学者我确实需要找到附加的片段并且使用 fragmentstateviewpager 不使用 hack 是不可能的,必须有一些原因为什么它在某些而不是在其他人中工作,有时不完全

编辑 2

所以我还在摆弄这个,我几乎没有回复所以让我们稍微充实一下所以我在主要 activity 中添加了菜单布局,就像这样

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

并且我在片段的 onCreateView 中调用了 setHasOptionsMenu(true),这非常有效,但我有大约 20 个片段要循环,当我将它添加到其他片段时它失败了,它要么什么也不做,要么使视图空白或在极少数情况下有效,但对我来说,我的代码没问题,也许它是生命周期的事情,我尝试从片段的 onCreateOptionsMenu 调用它并获得相同的结果,我尝试不从 onCreateOptions 的 MainActivity 调用任何东西除了膨胀菜单并允许片段调用搜索 activity 使用

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 好的,通过添加一些,检查它,添加更多,检查它,我的 parent 片段似乎有问题所以我有主要的 activity 4 个片段,每个片段都有一个片段状态寻呼机如果我将查询侦听器的方法添加到第一个 parent 片段中的前 7 个左右的片段中,它们将保存 7 个左右的片段,如果我随后将这些方法添加到下一组 7 个左右的片段中,它们都可以很好地工作在第二个 parent 只有第二个 parents child 片段工作,如果我然后退出我的应用程序并再次打开它只有第一个 parents 片段工作,将继续调查任何帮助表示感谢我很快就会 post 我的 parent 片段的代码。

编辑 4 只是要添加我用于 parent 片段的代码和来自我的主要 activity

的 fragmentstatepager

所以从我的 Main activity 我这样设置 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);
    }
}

我的 parent 片段看起来像这样

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

仍在为此苦苦挣扎,我终其一生都无法弄清楚为什么它会在很多片段中工作,直到我将它添加到下一组,它与相同的代码相同,它必须只是初始化要求它的最后片段有人可以在这里帮助我吗? 感谢您的帮助

基本上,在使用片段时必须牢记一件事:不要保留对片段的引用:只需创建它们并添加到您的布局中,或提供给您的 ViewPager,然后使用其他方法检索它们,例如 FragmentManager.findFragmentBy...

也就是说,您的代码应该是(让我用两个片段来简化):

主要activity

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 Fragment 中使用的代码与前一个非常相似,但您必须使用子 fragmentManager(就像您在代码中所做的那样),并且不要将您的片段保留在a List,让系统在需要的时候创建。

好的,我修复了它,所以问题是 parent fragmentstatepager 将 fragmentA + fragmentB 加载到内存中,然后 child fragmentstatepagers 加载自己的 childfragmentA + childfragmentB 所以我们现在有 2 parents 和 4 children,从 child 片段调用 onPrepareOptionsMenu 所以第一个被加载 childfragmentA(child of fragmentA) 然后 childFragmentA(child of fragmentB) 被加载并窃取搜索视图,我的 'fix' 因为这可能有点粗糙我是自学的而且我'我不是很清楚如何管理内存,或者如果保留引用不好,我离题了,在 parent 片段中,我使用

检查哪个片段可见
setMenuVisibility(final boolean visible)

并在那里我设置了一个 public 静态布尔值并在我的 child 片段中检查它并且它对我来说完美无缺,如前所述,这可能是一件糟糕的事情,希望这里有人可以给出更好的解决方案

检查哪个 parent 可见

public static boolean tabFragOneVisible;

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

检查parent是否可见连接搜索视图

@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 适用于多个 Fragment 的人。我发现 onQueryTextListener 可以在 Fragment 1(最初创建 SearchView 的地方)上工作,但不会在 Fragment 2,3 等上触发

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