在ViewPager中重新加载fragment时出现的问题

3

我在ViewPager中遇到了片段的问题。在我的应用程序中,我使用FragmentStatePagerAdapter实现了4个选项卡。 这是我的SectionsPageAdapter.java文件

public class SectionsPageAdapter extends FragmentStatePagerAdapter {

private String fragment0 = "";
private Fragment fragAt0;
private FragmentManager manager;
private String[] tabNames;
Context context;


public SectionsPageAdapter(FragmentManager fm, Context ctx, String lastFrag) {
    super(fm);
    context = ctx;
    tabNames = ctx.getResources().getStringArray(R.array.tabs_name);
    this.manager = fm;
    this.listener = new fragmentChangeListener();
    fragment0 = lastFrag;
}


@Override
public Fragment getItem(int position) {
    switch (position) {
        case 0:
            return ActivityTypeFragment.newInstance(0);
        case 1:
            return EventsFragment.newInstance();
        case 2:
            return CalendarFragment.newInstance();
        case 3:
            if(fragAt0 == null){

                switch(fragment0){
                    case "Chart":
                        fragAt0 = ChartFragment.newInstance(listener);
                        break;
                    case "Hour":
                        fragAt0 = HourChartFragment.newInstance(listener);
                        break;
                    case "Daily":
                        fragAt0 = DailyChartFragment.newInstance(listener);
                        break;
                    default:
                        fragAt0 = ChartFragment.newInstance(listener);
                }
            }
            return fragAt0;
        default:
            return ActivityTypeFragment.newInstance(0);
    }
}

@Override
public int getCount() {
    return 4;
}

@Nullable
@Override
public CharSequence getPageTitle(int position) {
    return tabNames[position];
}

@Override
public int getItemPosition(@NonNull Object object) {
    if (object instanceof ChartFragment && fragAt0 instanceof DailyChartFragment
        || object instanceof HourChartFragment && fragAt0 instanceof DailyChartFragment)
    {
        return POSITION_NONE;
    }
    else if (object instanceof DailyChartFragment && fragAt0 instanceof ChartFragment
            || object instanceof HourChartFragment && fragAt0 instanceof ChartFragment){
        return POSITION_NONE;
    }
    else if (object instanceof HourChartFragment && fragAt0 instanceof ChartFragment)
    {
        return POSITION_NONE;
    }
    else if (object instanceof ChartFragment && fragAt0 instanceof HourChartFragment
            || object instanceof DailyChartFragment && fragAt0 instanceof HourChartFragment)
    {
        return POSITION_NONE;
    }

    return POSITION_NONE;
}

public interface nextFragmentListener {
    void fragment0Changed(String newFragmentIdentification, FragmentManager fragmentManager);
}
private nextFragmentListener listener;

private final class fragmentChangeListener implements nextFragmentListener {


    @Override
    public void fragment0Changed(String fragment, FragmentManager fm) {
        fragment0 = fragment;

        manager.beginTransaction().remove(fragAt0).commitNow();
        switch (fragment) {
            case "Chart":
                fragAt0 = ChartFragment.newInstance(listener);

                break;
            case "Daily":
                fragAt0 = DailyChartFragment.newInstance(listener);
                break;
            case "Hour":
                fragAt0 = HourChartFragment.newInstance(listener);
                break;
        }
        SectionsPageAdapter.this.notifyDataSetChanged();
    }
}

public String getFragmentName()
{
    return fragment0;
}

}

在最后一个选项卡中,我有一个片段 - ChartFragment,在其中有一个下拉菜单可以选择另一个图表。当用户选择另一个图表时,通过调用SectionsPageAdapter类中的fragment0Changed方法,在此标签页中重新加载另一个图表。我在https://dev59.com/H2sz5IYBdhLWcg3wsaAN#27304530上找到了这个解决方案。
以下是我在每个要出现在Charts选项卡中的片段中拥有的onItemSelected函数。
@Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
        if (view != null) {
            String selectedMenu = ((TextView) view).getText().toString();
            if (selectedMenu == getString(R.string.best_appealing_chart)) {
                LoadBestAppealingChart();
            } else if (selectedMenu == getString(R.string.hour_chart)) {
                chartListener.fragment0Changed("Hour", getActivity().getSupportFragmentManager());
            }
            else
            {
                chartListener.fragment0Changed("Daily", getActivity().getSupportFragmentManager());
            }
        }
        else {
            LoadBestAppealingChart();
        }
    }

所以,在我旋转设备之前,一切都正常工作,但在那之后选择另一个图表就无法正常工作了。应用程序会抛出异常:

java.lang.IllegalStateException: Fragment host has been destroyed 
at android.support.v4.app.FragmentManagerImpl.ensureExecReady(FragmentManager.java:2183)
        at android.support.v4.app.FragmentManagerImpl.execSingleAction(FragmentManager.java:2211)
        at android.support.v4.app.BackStackRecord.commitNow(BackStackRecord.java:643).

我已阅读文章https://www.androiddesignpatterns.com/2013/08/fragment-transaction-commit-state-loss.html,,但在我的情况下,我没有异步方法来替换片段,也没有在Activity生命周期方法中调用它。我在我的Spinner的onSelectionChanged方法中进行片段事务。我尝试过使用commitNowAllowingStateLoss(),但并没有改善情况,它只是没有抛出异常,片段仍然没有重新加载;将getSupportFragmentManager()参数传递给fragment0Changed方法也没有帮助,但即使我使用简单的commitNow()方法,这样做也不会抛出任何异常。但是,在旋转后选择应用程序的第一个或第二个选项卡,然后转到第四个选项卡(图表选项卡),然后我可以轻松地切换(重新加载)我的片段。有趣的是,切换到第三个选项卡(日历选项卡)也没有帮助。在切换到第三个选项卡并返回第四个选项卡之后,切换片段仍然没有重新加载。

在 FragmentPagerAdapter 中,不应该保留对任何片段实例的引用,请参见 #3 https://proandroiddev.com/the-seven-actually-10-cardinal-sins-of-android-development-491d2f64c8e0 - EpicPandaForce
2个回答

1

我认为在Android上,通过传递侦听器与Fragment通信是一个常见的错误。Fragment上的侦听器必须由Activity或子Fragment实现。因此,您必须使您的Activity或Fragment实现NextFragmentListener... 其次,永远不要引用ViewPager上的Fragment,否则会泄漏旧的Fragment0。


0

公共类SubAdapter扩展自FragmentStatePagerAdapter {

/ * 只需在super()调用中传递行为,以便每次恢复方法调用时您都可以重新加载任何所需的内容 但是您应该使用扩展的子类 * /

private String tile_list [];

public SubAdapter (FragmentManager fm, String[] tile_list)
{

    super(fm,FragmentStatePagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
    this.tile_list = tile_list;
}

@Override
public Fragment getItem(int position)
{
    Fragment fragment;
    switch (position)
    {
        case 0:
            fragment=new new_fragment();
            break;

          default:
              fragment=new new_fragment();

    }
    return fragment;
}

@Override
public int getCount()
{
    return tile_list.length;
}

@Nullable
@Override
public CharSequence getPageTitle(int position)
{
    return tile_list[position];
}

}


在FragmentPagerAdapter或FragmentStatePagerAdapter中不应该持有对Fragment的引用。 - EpicPandaForce

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接