Android Widget SearchView异常:ViewPager随键盘触发重复加载求助
看起来你遇到的问题是软键盘的显示/隐藏触发了ViewPager页面视图的重建,进而重复执行数据加载逻辑。这通常和窗口布局变化导致的ViewPager重绘以及PagerAdapter的实现方式有关,下面是几个针对性的解决方案:
1. 优化PagerAdapter的实现,避免不必要的视图重建
如果你的ViewPager使用的是旧版的PagerAdapter(重写getView()方法),这种Adapter在布局发生变化时很容易重新创建视图。建议换成:
FragmentPagerAdapter:适合页面较少的场景,会缓存Fragment实例,不会频繁重建FragmentStatePagerAdapter:适合页面较多的场景,会在页面不可见时销毁Fragment的视图,但保留状态
如果必须使用自定义PagerAdapter,一定要确保在getView()中做好视图复用:先通过convertView获取缓存的视图,只有当视图为空时才创建新视图并加载数据,示例代码:
@Override public View getView(int position, View convertView, ViewGroup container) { ViewHolder holder; if (convertView == null) { // 仅在视图为空时初始化布局 convertView = LayoutInflater.from(context).inflate(R.layout.item_page, container, false); holder = new ViewHolder(convertView); convertView.setTag(holder); // 这里执行首次数据加载 loadData(position, holder); } else { holder = (ViewHolder) convertView.getTag(); // 复用视图时仅更新数据(如果需要),不要重复加载网络/本地数据 updateData(position, holder); } return convertView; }
2. 调整窗口软键盘模式,减少布局重排
软键盘弹出时默认会调整窗口布局(adjustResize),这会触发CoordinatorLayout和AppBarLayout的重新测量,进而影响ViewPager的布局。可以在AndroidManifest.xml中给对应的Activity添加windowSoftInputMode属性:
<activity android:name=".YourActivity" android:windowSoftInputMode="adjustPan"> </activity>
adjustPan:软键盘弹出时会将整个页面上移,不会调整布局大小,避免触发ViewPager的重绘- 如果
adjustPan影响布局美观,也可以尝试adjustNothing,但软键盘可能会遮挡部分内容,需要结合需求选择
3. 检查AppBarLayout和CollapsingToolbarLayout的配置
你的布局中CollapsingToolbarLayout的scrollFlags设置为scroll|exitUntilCollapsed|enterAlwaysCollapsed,同时Toolbar的scrollFlags是scroll|enterAlways,这两个设置可能存在冲突,导致软键盘变化时AppBarLayout异常布局,进而触发下面ViewPager的重绘。可以尝试调整:
- 去掉
CollapsingToolbarLayout的enterAlwaysCollapsed,改为scroll|exitUntilCollapsed - 确保
ViewPager所在的FrameLayout的layout_behavior正确设置为@string/appbar_scrolling_view_behavior(你的代码里已经设置了,但可以确认是否有拼写错误)
另外,CoordinatorLayout的fitsSystemWindows="false"和AppBarLayout的fitsSystemWindows="true"可能存在适配问题,尝试将CoordinatorLayout的fitsSystemWindows改为true,看看是否能缓解布局波动。
4. 给数据加载逻辑加缓存,从根源避免重复加载
不管视图是否重建,都应该确保数据加载逻辑是幂等的。可以在Adapter或ViewModel中维护一个数据缓存集合,加载前先判断对应位置的数据是否已经存在:
private List<DataModel> mDataCache = new ArrayList<>(); private void loadData(int position, ViewHolder holder) { if (position < mDataCache.size() && mDataCache.get(position) != null) { // 已有缓存,直接复用 holder.bindData(mDataCache.get(position)); return; } // 无缓存时执行加载逻辑 requestDataFromNetwork(position, new Callback() { @Override public void onSuccess(DataModel data) { if (position < mDataCache.size()) { mDataCache.set(position, data); } else { mDataCache.add(data); } holder.bindData(data); } }); }
这些方案可以逐步尝试,优先从Adapter优化和软键盘模式调整入手,这两个是最常见的解决思路。
内容的提问来源于stack exchange,提问作者noyal_asok

