ViewPager 缓存使 SearchView 结果看起来很奇怪

ViewPager Cache is making SearchView results appear weird

小语境

我在 activity_main.xml

中有一个 SearchView 和一个 ViewPager
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/constraintLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".activity.MainActivity">

    <androidx.appcompat.widget.SearchView
        android:id="@+id/homeSearchView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="8dp"
        app:layout_constraintBottom_toTopOf="@id/viewPager"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <androidx.viewpager.widget.ViewPager
        android:id="@+id/viewPager"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toTopOf="@id/homeMenuIcon"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/homeSearchView" />


    <ImageView
        android:id="@+id/homeMenuIcon"
        android:layout_width="36dp"
        android:layout_height="36dp"
        android:layout_margin="8dp"
        android:contentDescription="Overflow Menu Icon"
        android:scaleType="fitXY"
        android:src="@drawable/ic_menu"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@id/viewPager"
        tools:ignore="HardcodedText" />
</androidx.constraintlayout.widget.ConstraintLayout>

我在 MainActivity.java

中将 OnQueryTextListener 附加到 SearchView

ViewPager viewPager = findViewById(R.id.viewPager);
List<Quote> allQuotesList = getQuotes();//From `Volley` Request
QuoteViewPagerAdapter adapter = new QuoteViewPagerAdapter(getSupportFragmentManager(), allQuotesList);
viewPager.setAdapter(adapter);


SearchView searchView = findViewById(R.id.homeSearchView);
        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                getFilter().filter(query);
                return false;
            }

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

 private Filter getFilter() {
        return new Filter() {
            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                ArrayList<Quote> filteredResults = new ArrayList<>();

                if (constraint.toString().isEmpty())
                    filteredResults.addAll(allQuotesList);
                else
                    for (Quote quote : allQuotesList) {
                        if (quote.getQuote().toLowerCase().contains(constraint.toString().toLowerCase())
                                || quote.getAuthor().toLowerCase().contains(constraint.toString().toLowerCase()))
                            filteredResults.add(quote);
                    }

                FilterResults filterResult = new FilterResults();
                filterResult.values = filteredResults;

                return filterResult;
            }

            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {
                adapter.setQuoteList((List<Quote>) results.values);
                adapter.notifyDataSetChanged();
            }
        };
    }

这里是QuoteViewPagerAdapter.java

public class QuoteViewPagerAdapter extends FragmentPagerAdapter {
    private List<Quote> quoteList;

    public QuoteViewPagerAdapter(FragmentManager fm, List<Quote> fragmentList) {
        super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
        quoteList = fragmentList;
    }

    @androidx.annotation.NonNull
    @Override
    public Fragment getItem(int position) {
        return QuoteFragment.newInstance(quoteList.get(position));
    }

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

    @Override
    public int getItemPosition(@androidx.annotation.NonNull Object object) {
        return POSITION_NONE;
    }

    public void setQuoteList(List<Quote> quoteList) {
        this.quoteList = quoteList;
    }
}

这里是Quote.java

public class Quote {

    private String quote;
    private String author;

    public Quote() {
    }

    public Quote(String quote, String author) {
        this.quote = quote;
        this.author = author;
    }

    public String getQuote() {
        return quote;
    }

    public void setQuote(String quote) {
        this.quote = quote;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }
}

问题

搜索内容时,QuoteViewPagerAdapter 中的 quoteList (List<Quote>) 会更新为 setQuoteList()。所以,getCount() returns 新尺寸。

但是,旧片段(其中 2 个)保留在 ViewPager 中。这使得搜索结果在滚动 ViewPager 2 次后出现。此外,这会导致最后 2 个结果被忽略。

此外,如果只有 1 个搜索结果的大小,ViewPager 会冻结,无法滚动(因为 getCount() returns 1 所以 ViewPager 只显示旧的第一个片段)

我试过的

//inside publishResults()
adapter = null;
viewPager.setAdapter(null);
viewPager.removeAllViews();
viewPager.removeAllViewsInLayout();
viewPager.destroyDrawingCache();

adapter = new QuoteViewPagerAdapter(getSupportFragmentManager(), (List<Quote>) results.values);
viewPager.setAdapter(adapter);
adapter.notifyDataSetChanged();

//inside onCreate()

viewPager.setSaveFromParentEnabled(false);
viewPager.setSaveEnabled(false);

预期行为

ViewPager 显示从位置 0 开始的搜索结果的新列表

期待 Whosebug 社区的帮助。提前致谢。

通过在 QuoteViewPagerAdapter.java

中将 FragmentPagerAdapter 更改为 FragmentStatePagerAdapter,它按预期工作

有点晚了,但是,为未来的读者写下这个答案...