ViewPager+Fragment动态刷新问题

在我们的项目开发中会经常使用到ViewPager+Fragment来实现特定的UI效果,但是当Fragment需要动态增加,删除过内容变更时,会出现Fragment页面刷新失效的情况

如下:

@BindView(R.id.viewpager)     ViewPager   viewpager;

List fragments  = new ArrayList<>();

private void setupViewPager(List list_key) {
    fragments.clear();
    for (int i = 0; i < list_key.size(); i++) {
        fragments.add(MyFragment.newInstance(list_key.get(i)));
    }
    viewpager.setAdapter(new MyPagerAdapter(getChildFragmentManager(), fragments));
    viewpager.setOffscreenPageLimit(2);
}

class MyPagerAdapter extends FragmentPagerAdapter {

    private List fragments;

    public MyPagerAdapter(FragmentManager fm, List fragments) {
        super(fm);
        this.fragments = fragments;
    }

    @Override
    public Fragment getItem(int position) {
        return fragments.get(position);
    }

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

}

//创建 主页tab
public static MyFragment newInstance(String key) {
    FragmentHomeUser fragment = new FragmentHomeUser();
    Bundle           args     = new Bundle();
    args.putString("key", key);
    fragment.setArguments(args);
    return fragment;
}

public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_homeuser, container, false);
    String key = getArguments().getString("key", "");

    return view;
}

当我们需要变更fragments中的Fragment时,即便
Bundle args = new Bundle();
args.putString(“key”, key);
fragment.setArguments(args);
中传入新的key

String key = getArguments().getString(“key”, “”);
获取到的值依然是就的key值

后来发现是因为FragmentPagerAdapter 没有刷新导致

要解决这个问题要针对FragmentPagerAdapter 做一些优化处理

方式一:

1、清除FragmentPagerAdapter缓存,重新添加

private void clearViewPager() {
    //先保证ViewPager之前已设置过Adapter,这样才有可能存在缓存
    if (viewpager.getAdapter() != null) {
        //获取FragmentManager实现类的class对象,这里指的就是FragmentManagerImpl
        Class aClass = getChildFragmentManager().getClass();
        try {
            //1.获取其mAdded字段
            Field field = aClass.getDeclaredField("mAdded");
            field.setAccessible(true);
            //强转成ArrayList
            ArrayList list = (ArrayList) field.get(getChildFragmentManager());
            //清空缓存
            list.clear();

            //2.获取mActive字段
            field = aClass.getDeclaredField("mActive");
            field.setAccessible(true);
            //强转成SparseArray
            SparseArray array = (SparseArray) field.get(getChildFragmentManager());
            //清空缓存
            array.clear();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

private void setupViewPager(List list_key) {
    fragments.clear();
    for (int i = 0; i < list_key.size(); i++) {
        fragments.add(MyFragment.newInstance(list_key.get(i)));
    }
    clearViewPager();
    viewpager.setAdapter(new MyPagerAdapter(getChildFragmentManager(), fragments));
    viewpager.setOffscreenPageLimit(2);
}

2、重写FragmentPagerAdapter的getItemPosition方法

class MyPagerAdapter extends FragmentPagerAdapter {

    private List fragments;

    public MyPagerAdapter(FragmentManager fm, List fragments) {
        super(fm);
        this.fragments = fragments;
        notifyDataSetChanged();
    }

    @Override
    public Fragment getItem(int position) {
        return fragments.get(position);
    }

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

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

    @Override
    public int getItemPosition(@NonNull Object object) {
        // 否则返回状态值 POSITION_NONE
        return POSITION_NONE;
    }
}

以上可以解决Fragment的动态刷新问题,但新的问题出现了,在刷新时,由于Fragment要清除后重新载入,在UI效果上会出现闪屏现象,下面我们在来解决这个问题

方式二:

在初始化时,对比fragments和list_key需要生成的Fragment列表,已经添加到FragmentPagerAdapter 中的Fragment,只变更key值,根据key值刷新Fragment,需要添加的Fragment则使用fragments.add(MyFragment.newInstance(list_key.get(i)));添加新的Fragment,最后通过remove方法移出多余的Fragment

private void setupViewPager(List list_key) {
    if (fragments.size() > 0) {
        for (int i = 0; i < list_key.size(); i++) {
            if (fragments.size() > i) {
                if (fragments.get(i).getKey().equals(list_key.get(i))) {
                    Bundle args = new Bundle();
                    args.putString("key", list_key.get(i));
                    fragments.get(i).setArguments(args);
                }
            } else {
                fragments.add(MyFragment.newInstance(list_key.get(i)));
            }
        }
    } else {
        for (int i = 0; i < list_key.size(); i++) {
            fragments.add(MyFragment.newInstance(list_key.get(i)));
        }
    }
    remove(fragments, list_key);
    viewpager.setAdapter(new MyPagerAdapter(getChildFragmentManager(), fragments));
    viewpager.setOffscreenPageLimit(2);
}

/**
 * 移除
 */
private void remove(List fragments, List array) {
    for (Iterator it = fragments.iterator(); it.hasNext(); ) {
        MayFragment entry = it.next();
        String           key  = entry.getArguments().getString("key");
        Logs.e("entry.key = " + key + ", isInArray = " + isInArray(array, key));
        if (!isInArray(array, key)) {
            Logs.e("删除-" + key);
            it.remove();
        }
    }
}

private boolean isInArray(List array, String key) {
    for (int i = 0; i < array.size(); i++) {
        if (array.get(i).equals(key)) {
            return true;
        }
    }
    return false;
}

然后重写FragmentPagerAdapter 的getItemPosition方法,key值一致测不需要刷新,不一致的需要通过return POSITION_NONE;刷新Fragment

class MyPagerAdapter extends FragmentPagerAdapter {

    private List fragments;

    public MyPagerAdapter(FragmentManager fm, List fragments) {
        super(fm);
        this.fragments = fragments;
        notifyDataSetChanged();
    }

    @Override
    public Fragment getItem(int position) {
        return fragments.get(position);
    }

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

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

    @Override
    public int getItemPosition(@NonNull Object object) {
        MyFragment info     = (MyFragment) object;
        int              position = getFragmentPosition(fragments, info.getKey());
        if (position != -1) {
            // 如果当前 item 未被 remove,则返回 item 的真实 position
            return position;
        } else {
            // 否则返回状态值 POSITION_NONE
            return POSITION_NONE;
        }
    }
}

public int getFragmentPosition(List fragments, String key) {
    for (int i = 0; i < fragments.size(); i++) {
        if (key.equals(fragments.get(i).getKey())) {
            return i;
        }
    }
    return -1;
}

以上既能刷新Fragment有可避免已有Fragment刷新时闪屏问题

你可能感兴趣的:(ui布局)