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
,它按预期工作
有点晚了,但是,为未来的读者写下这个答案...
小语境
我在 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
,它按预期工作
有点晚了,但是,为未来的读者写下这个答案...