java - 接下来在已经运行的Android ViewPager中插入新的Fragment

标签 java android android-fragments

尝试将片段动态添加到Android ViewPager中的不同页面。

动态地将片段添加到片段列表的末尾可以很好地工作,但是尝试将其添加到下一个插槽(当前可见页面之后的看不见的页面)。我尝试将其添加到片段的数组列表中,并使用notifyDataSetChanged,并尝试在将每个片段设置为上一个项目之后在每个片段上使用set。

编辑:更新的代码

class MainPagerAdapter extends FragmentPagerAdapter {

    public MainPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public PageFragment getItem(int position) {
        return PageFragment.newInstance(Datamart.getInstance().getURLs().get(position));
    }

    @Override
    public int getCount() {
        return Datamart.getInstance().getURLs().size();
    }

    @Override
    public int getItemPosition(Object object) {
        PageFragment pageFragment = (PageFragment) object;
        for ( int i = 0; i < getCount(); i++ ) {
            if ( pageFragment.getURL().equals( Datamart.getInstance().getURLs().get(i) ) ) {
                return i;
            }
        }
        return POSITION_NONE;
    }
}


在Datamart中:

public class Datamart {

    static Datamart instance;

    private ArrayList<String> URLs;
    private MainPagerAdapter mainPagerAdapter;
    private ViewPager viewPager;

    public Datamart() {
        URLs = new ArrayList<>();
    }

    public static Datamart getInstance() {
        if (instance == null) {
            instance = new Datamart();
        }
        return instance;
    }

    public MainPagerAdapter getMainPagerAdapter() {
        return mainPagerAdapter;
    }

    public void setMainPagerAdapter(MainPagerAdapter mainPagerAdapter) {
        this.mainPagerAdapter = mainPagerAdapter;
    }

    public ViewPager getViewPager() {
        return viewPager;
    }

    public void setViewPager(ViewPager viewPager) {
        this.viewPager = viewPager;
    }

    public void addToEnd( String URL ) {
        URLs.add(URL);
        mainPagerAdapter.notifyDataSetChanged();
    }

    public void addNext( String URL ) {
        URLs.add(viewPager.getCurrentItem() + 1, URL);
        mainPagerAdapter.notifyDataSetChanged();
    }

    public ArrayList<String> getURLs() {
        return URLs;
    }

    public void setURLs(ArrayList<String> URLs) {
        this.URLs = URLs;
    }
}

最佳答案

ViewPager尽最大努力尝试跟踪所有片段的去向,但由于将片段插入中间而没有告知,您感到困惑。

让我们做一个例子。假设您有两页,那么您将显示第一页,第二页是右侧的屏幕外页。您第一页有fragment0,第二页有fragment1

首先,请记住,由于ViewPager正在左右管理屏幕外页面,因此它已经认为知道第二个页面片段是什么,即fragment1

在现有页面片段之间插入片段时,ViewPager不会立即询问您第二个位置的片段,而是要询问第二个位置的片段是否已更改。

这是getItemPosition()的来源。您没有在getItemPosition()中实现FragmentPagerAdapter,所以getItemPosition()的默认行为是返回POSITION_UNCHANGED。 (如您所见,这就是为什么在末尾添加片段不会导致错误的原因。)

因此,当您调用notifyDataSetChanged()时,ViewPager调用了getCount()并看到有两个页面,而不是两个页面。然后,它为第0页和第1页(它知道的页面)调用getItemPosition(),并且您的默认实现告诉它什么都没有改变。

但是确实发生了变化,您在两个现有页面的中间插入了一个页面/片段。 ViewPager询问您第二页是否更改,并且您的getItemPosition()应该返回了2而不是POSITION_UNCHANGED

现在,由于您的getCount()返回了3而不是2,因此ViewPager知道末尾有一个新页面,它不知道,因此它调用getItem()来获取新片段。

这是发生错误的地方。您的getItem()方法在第3页返回了fragment1,并且ViewPager阻塞了,因为您将它已经知道的片段交给了它。具体来说,它将片段的标签用于一些内部管理。它在页面的容器ID和项目位置(页面编号)之外创建标签。因此,在任何给定时间,它都期望(a)标签为空,或者(b)标签将与根据容器ID和商品位置已经计算出的值相同。这些条件都不是正确的,所以这就是抛出IllegalStateException的原因。

那么如何解决这个问题?

您实现一个做正确的事情的getItemPosition()。调用getItemPosition()时,将扫描片段列表,找到匹配的片段时,将返回片段的索引。如果删除了一个片段,使得列表中没有匹配的片段,则返回POSITION_NONE告诉ViewPager应该删除该页面。 ViewPager然后将调用您的getItem()方法以获取新页面。这样,ViewPager可以始终与适配器保持同步。



编写FragmentPagerAdapter时,我什至不使用模型中的片段。如果我正在编写您的适配器,那么我将只有一个URL列表,因为看起来每个页面/片段都有其自己的唯一URL。

我还将在fragment类上实现一个getUrl()方法,以获取用于创建该fragment的URL。

因此,对于getItemPosition(),我将在传入的片段上调用getUrl(),然后在适配器的列表中搜索该URL。然后,我将返回列表中URL的索引,如果不存在,则返回POSITION_NONE

然后在getItem()中,我将使用传入的列表位置处的URL实例化一个新片段。我的规则是,直到ViewPager通过调用getItem()专门请求它之前,我才不会实例化一个片段。

这样,只有ViewPager会访问这些片段,而我不会遇到这些类型的问题。

另外,在ViewPager调用startUpdate()到调用finishUpdate()的时间之间,请勿对适配器模型进行任何更改。这就是ViewPager告诉适配器它在确定所有页面片段的去向的“关键部分”中的方式。

PagerAdapter可以忍受。在getCount()getItemPosition()getItem()方法中放入一些调试日志,以便您了解ViewPager如何使用适配器管理其页面。

关于java - 接下来在已经运行的Android ViewPager中插入新的Fragment,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30282516/

相关文章:

java - 获取特定 xml 元素的 xsd 限制

android - WebViewFragment webView 在执行 FragmentTransaction 后为 null

android - 如何对 ViewPager 中的所有页面使用单个 Fragment?

java - 从 JSP 调用后端 Java 类

java - Spring 启动 + jackson + LocalDateTime : Date not parsed correctly

android - 使用 MediaRecorder 在我的 droidx 上录制的音频质量很差,为什么?

android - 程序包重命名后无法安装应用程序

android - Android 中 map fragment 上显示的黑线

java - 泛型数组转换

java - 从 json 解析设置 textview 时出错