ViewPager FragmentPagerAdapter在系统杀死应用后重建时UI不刷新的问题

发布于:2025-05-01 ⋅ 阅读:(21) ⋅ 点赞:(0)
解决方案

通过重写getItemId方法,返回Fragment的hashCode

@Override
public long getItemId(int position) {
    /**
     * 恢复状态重建时,新的 Fragment 不刷新UI。
     * 原因:instantiateItem 中通过 mFragmentManager.findFragmentByTag(name) 无法找到新的 Fragment,
     * 因为 name 是由 container.getId() +  getItemId 组成(其中getItemId默认返回position),二者都没变化
     * 为了让mFragmentManager正确找到新Fragment,那就让 getItemId(即name) 与 Fragment 绑定,而不仅与position绑定
     * 这样上述问题得解
     */
    return fragmentList.get(position).hashCode();
}
原理解析
一、默认机制的问题根源

FragmentPagerAdapter中,instantiateItem方法会使用makeFragmentName生成Fragment的唯一标识Tag,组合规则如下:

"android:switcher:" + viewId + ":" + getItemId(position)
  • 默认行为:父类的getItemId()直接返回position。当Activity重建时,相同位置的新旧Fragment生成相同的Tag,导致系统优先从FragmentManager缓存中复用旧实例,而不会调用getItem()创建新Fragment。
二、解决方案的核心逻辑

通过重写getItemId(),使其返回值与Fragment对象本身相关联:

@Override
public long getItemId(int position) {
    return fragmentList.get(position).hashCode();
}

实现效果

  1. 唯一Tag生成:即使position相同,只要Fragment对象不同,hashCode必然不同,新旧Fragment的Tag不同;
  2. 阻断缓存复用:系统通过findFragmentByTag查找失败,强制调用getItem()创建新Fragment实例;
  3. 数据一致性保证:新Fragment从最新数据源初始化,避免恢复旧状态导致的UI错乱。
三、源码级验证

查看FragmentPagerAdapter.instantiateItem()的关键逻辑:

// 生成唯一标识Tag
final long itemId = getItemId(position);
String name = makeFragmentName(container.getId(), itemId);

// 优先从缓存中查找Fragment
Fragment fragment = mFragmentManager.findFragmentByTag(name);
if (fragment != null) {
    mCurTransaction.attach(fragment); // 命中缓存,直接复用旧实例
} else {
    fragment = getItem(position);       // 未命中,创建新实例
    mCurTransaction.add(..., name);
}

在这里插入图片描述
在这里插入图片描述

四、示例代码
public class ServerPagerAdapter extends FragmentPagerAdapter {
    private final List<ServerFragment> fragmentList;

    @Override
    public long getItemId(int position) {
        return fragmentList.get(position).hashCode(); // 绑定对象哈希值
    }

    // 其他代码保持默认实现即可
}

总结

通过重写getItemId改变Fragment的Tag生成规则,从根本上阻断了系统对旧Fragment实例的复用机制。此方案以最小代码改动实现了数据与UI的强一致性,适用于动态数据场景的ViewPager适配。但需注意:长期持有大量Fragment对象可能引发内存压力,建议结合FragmentStatePagerAdapter使用以优化资源回收。


网站公告

今日签到

点亮在社区的每一天
去签到