Viewpager:如果页面被删除,则下一页内容将获取已删除的页面内容

mik*_*enz 7 android adapter android-fragments android-viewpager

(如果有人需要更多信息,或者更好的描述让我知道)

您好,我在这里包含了viewPagerLibrary:http://viewpagerindicator.com/#introduction 今天在我的项目中.

不,我得到一个非常奇怪的问题:如果我添加一个网站或页面(让我们在接下来的几行中调用它)并再次删除它一切都可以.但是,如果我尝试添加不同的页面(那些页面是实现BaseFragment类的不同Fragements),则会显示第一页的内容.如果我添加几个页面并在这些页面之间删除一个页面,则会发生同样的事情.删除页面之后的页面现在显示已删除的页面内容.

这个bug的一个例子: 现在的问题是.如果我在FragmentB之后添加FragmentA,那么我删除FragmentA,FragmentB获取FragmentA的视图/内容.奇怪的是,对象是正确的(所以适配器返回正确的对象),标题也是正确的.

在我的主要部分,我用这种方式创建我的寻呼机,指示器和适配器:

    Cfg.mAdapter = new FragmentAdapter(getSupportFragmentManager());

    Cfg.mPager = (ViewPager)findViewById(R.id.pager);
    Cfg.mPager.setAdapter(Cfg.mAdapter);

    Cfg.mIndicator = (TabPageIndicator)findViewById(R.id.indicator);
    Cfg.mIndicator.setViewPager(Cfg.mPager);

    //We set this on the indicator, NOT the pager
    Cfg.mIndicator.setOnPageChangeListener(TabHelper.onPageChangeListener);
Run Code Online (Sandbox Code Playgroud)

(Cfg是一个静态文件,用于存储这些东西以供使用)

我的BaseFragment如下所示:

public class BaseFragment extends Fragment{

    public static int FILE_FRAGMENT = 0;
    public static int FTP_FRAGMENT = 1;
    public static int ADDFTP_FRAGMENT = 2;
    public static int PREVIEW_FRAGMENT = 3;
    public static int CSS_FRAGMENT = 4;
    public static int BOOKS_FRAGMENT = 5;
    public static int SNIPPETS_FRAGMENT = 6;

    //private int id;
    private int typ;
    private String title;

    public int getTyp() {
        return typ;
    }

    public void setTyp(int typ) {
        this.typ = typ;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }
}
Run Code Online (Sandbox Code Playgroud)

其中一个片段看起来像这样(我认为其他片段没有区别):

public class FtpFragment extends BaseFragment {
    private static RowLayout rowLayout_view;

    public FtpFragment() {
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        init_data();
    }

    public static void init_data()
    {
        //Remove child for update
        rowLayout_view.removeAllViews();

        List<FtpData> ftps = FtpStorage.getInstance().getFtps();

        if (ftps != null) {
            for (FtpData f : ftps) {
                View inflatedView;
                inflatedView = View.inflate(Cfg.ctx, R.layout.ftp, null);
                inflatedView.setOnClickListener(button_ftp_listener);
                inflatedView.setOnLongClickListener(button_ftp_longClickListener);
                inflatedView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, Converter.convertFromDPtoPixel(160.0f)));
                inflatedView.setTag(f);
                inflatedView.findViewById(R.id.book_imageview).setBackgroundDrawable(
                                Cfg.ctx.getResources().getDrawable(R.drawable.nopreview));


                ((TextView) inflatedView.findViewById(R.id.book_textview)).setText(f.nickname);

                rowLayout_view.addView(inflatedView);
            }
        }
    }

    @Override

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.fragment_ftp, container, false);
    rowLayout_view = (RowLayout) v.findViewById(R.id.rowLayout_ftps);
    return v;
}

@Override
public String getTitle() {
    return "FTPs";
}

@Override
public int getTyp() {
    return BaseFragment.FTP_FRAGMENT;
}

@Override
public void setTyp(int typ) {
    super.setTyp(typ);
}
Run Code Online (Sandbox Code Playgroud)

}

要删除或添加页面我称之为:

public static void addNewTab(BaseFragment fragment)
{
    Cfg.mAdapter.addItem(fragment);
    Cfg.mPager.setCurrentItem(Cfg.mAdapter.getCount());
    Cfg.mIndicator.notifyDataSetChanged();
}

public static void deleteActTab()
{
    Cfg.mAdapter.removeItem(Cfg.mAdapter.getActPage());
    Cfg.mIndicator.notifyDataSetChanged();
}
Run Code Online (Sandbox Code Playgroud)

那就是适配器:

public class FragmentAdapter extends FragmentPagerAdapter implements TitleProvider{
    public List<BaseFragment> fragments = new LinkedList<BaseFragment>();

    private int actPage;

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


    public void setActPage(int actPage) {
        Lg.d("setActPage: " + actPage + " : " + fragments.get(actPage).toString());
        this.actPage = actPage; 
    }

    public void addItem(BaseFragment fragment)
    {
        Lg.d("addItem: " + fragment.toString());
        fragments.add(fragment);
    }

    public void removeItem(int index)
    {
        if(index < getCount()){
            Lg.d("RemoveItem: " + index + " : " + fragments.get(index).toString());
            fragments.remove(index);
        }
    }

    public BaseFragment getActFragment()
    {
        return getItem(getActPage());
    }

    public int getActPage() {
        return actPage;
    }

    @Override
    public BaseFragment getItem(int position) {
        if(position < getCount())
        {
            Lg.v("getItem: " + fragments.get(position));
            return fragments.get(position);
        }
        else
            return null;
    }

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

    @Override
    public String getTitle(int position) {
        Lg.v("Get Title: " + fragments.get(position).getTitle());
        return fragments.get(position).getTitle();
    }

}
Run Code Online (Sandbox Code Playgroud)

是的,我希望有人可以帮助我.

如果我忘记了什么让我知道.

先谢谢你,迈克

mik*_*enz 2

好吧,我现在已经以一种黑客的方式解决了我的问题,但是是的,它正在工作;)。如果有人可以改进我的解决方案,请告诉我。对于我的新解决方案,我现在使用 CustomFragmentStatePagerAdapter 但它不会像应有的那样保存状态并将所有片段存储在列表中。如果用户有超过 50 个片段,这可能会导致内存问题,就像普通的 FragmentPagerAdapter 那样。如果有人可以将状态事物添加回我的解决方案而不删除我的修复,那就太好了。谢谢。

\n\n

这是我的CustomFragmentStatePagerAdapter.java

\n\n
package com.tundem.webLab.Adapter;\n\nimport java.util.ArrayList;\n\nimport android.os.Bundle;\nimport android.os.Parcelable;\nimport android.support.v4.app.Fragment;\nimport android.support.v4.app.FragmentManager;\nimport android.support.v4.app.FragmentTransaction;\nimport android.support.v4.view.PagerAdapter;\nimport android.util.Log;\nimport android.view.View;\nimport android.view.ViewGroup;\n\npublic abstract class CustomFragmentStatePagerAdapter extends PagerAdapter {\n    private static final String TAG = "FragmentStatePagerAdapter";\n    private static final boolean DEBUG = false;\n\n    private final FragmentManager mFragmentManager;\n    private FragmentTransaction mCurTransaction = null;\n\n    public ArrayList<Fragment.SavedState> mSavedState = new ArrayList<Fragment.SavedState>();\n    public ArrayList<Fragment> mFragments = new ArrayList<Fragment>();\n    private Fragment mCurrentPrimaryItem = null;\n\n    public CustomFragmentStatePagerAdapter(FragmentManager fm) {\n        mFragmentManager = fm;\n    }\n\n    /**\n     * Return the Fragment associated with a specified position.\n     */\n    public abstract Fragment getItem(int position);\n\n    @Override\n    public void startUpdate(ViewGroup container) {}\n\n    @Override\n    public Object instantiateItem(ViewGroup container, int position) {\n        // If we already have this item instantiated, there is nothing\n        // to do. This can happen when we are restoring the entire pager\n        // from its saved state, where the fragment manager has already\n        // taken care of restoring the fragments we previously had instantiated.\n\n        // DONE Remove of the add process of the old stuff\n        /* if (mFragments.size() > position) { Fragment f = mFragments.get(position); if (f != null) { return f; } } */\n\n        if (mCurTransaction == null) {\n            mCurTransaction = mFragmentManager.beginTransaction();\n        }\n\n        Fragment fragment = getItem(position);\n        if (DEBUG)\n            Log.v(TAG, "Adding item #" + position + ": f=" + fragment);\n        if (mSavedState.size() > position) {\n            Fragment.SavedState fss = mSavedState.get(position);\n            if (fss != null) {\n                try // DONE: Try Catch\n                {\n                    fragment.setInitialSavedState(fss);\n                } catch (Exception ex) {\n                    // Schon aktiv (kA was das hei\xc3\x9ft xD)\n                }\n            }\n        }\n        while (mFragments.size() <= position) {\n            mFragments.add(null);\n        }\n        fragment.setMenuVisibility(false);\n        mFragments.set(position, fragment);\n        mCurTransaction.add(container.getId(), fragment);\n\n        return fragment;\n    }\n\n    @Override\n    public void destroyItem(ViewGroup container, int position, Object object) {\n        Fragment fragment = (Fragment) object;\n\n        if (mCurTransaction == null) {\n            mCurTransaction = mFragmentManager.beginTransaction();\n        }\n        mCurTransaction.remove(fragment);\n\n        /*if (mCurTransaction == null) { mCurTransaction = mFragmentManager.beginTransaction(); } if (DEBUG) Log.v(TAG, "Removing item #" + position + ": f=" + object + " v=" + ((Fragment)\n         * object).getView()); while (mSavedState.size() <= position) { mSavedState.add(null); } mSavedState.set(position, mFragmentManager.saveFragmentInstanceState(fragment));\n         * mFragments.set(position, null); mCurTransaction.remove(fragment); */\n    }\n\n    @Override\n    public void setPrimaryItem(ViewGroup container, int position, Object object) {\n        Fragment fragment = (Fragment) object;\n        if (fragment != mCurrentPrimaryItem) {\n            if (mCurrentPrimaryItem != null) {\n                mCurrentPrimaryItem.setMenuVisibility(false);\n            }\n            if (fragment != null) {\n                fragment.setMenuVisibility(true);\n            }\n            mCurrentPrimaryItem = fragment;\n        }\n    }\n\n    @Override\n    public void finishUpdate(ViewGroup container) {\n        if (mCurTransaction != null) {\n            mCurTransaction.commitAllowingStateLoss();\n            mCurTransaction = null;\n            mFragmentManager.executePendingTransactions();\n        }\n    }\n\n    @Override\n    public boolean isViewFromObject(View view, Object object) {\n        return ((Fragment) object).getView() == view;\n    }\n\n    @Override\n    public Parcelable saveState() {\n        Bundle state = null;\n        if (mSavedState.size() > 0) {\n            state = new Bundle();\n            Fragment.SavedState[] fss = new Fragment.SavedState[mSavedState.size()];\n            mSavedState.toArray(fss);\n            state.putParcelableArray("states", fss);\n        }\n        for (int i = 0; i < mFragments.size(); i++) {\n            Fragment f = mFragments.get(i);\n            if (f != null) {\n                if (state == null) {\n                    state = new Bundle();\n                }\n                String key = "f" + i;\n                mFragmentManager.putFragment(state, key, f);\n            }\n        }\n        return state;\n    }\n\n    @Override\n    public void restoreState(Parcelable state, ClassLoader loader) {\n        if (state != null) {\n            Bundle bundle = (Bundle) state;\n            bundle.setClassLoader(loader);\n            Parcelable[] fss = bundle.getParcelableArray("states");\n            mSavedState.clear();\n            mFragments.clear();\n            if (fss != null) {\n                for (int i = 0; i < fss.length; i++) {\n                    mSavedState.add((Fragment.SavedState) fss[i]);\n                }\n            }\n            Iterable<String> keys = bundle.keySet();\n            for (String key : keys) {\n                if (key.startsWith("f")) {\n                    int index = Integer.parseInt(key.substring(1));\n                    Fragment f = mFragmentManager.getFragment(bundle, key);\n                    if (f != null) {\n                        while (mFragments.size() <= index) {\n                            mFragments.add(null);\n                        }\n                        f.setMenuVisibility(false);\n                        mFragments.set(index, f);\n                    } else {\n                        Log.w(TAG, "Bad fragment at key " + key);\n                    }\n                }\n            }\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

这是我正常的FragmentAdapter.java

\n\n
package com.tundem.webLab.Adapter;\n\nimport java.util.LinkedList;\nimport java.util.List;\n\nimport android.support.v4.app.FragmentManager;\n\nimport com.tundem.webLab.fragments.BaseFragment;\nimport com.viewpagerindicator.TitleProvider;\n\npublic class FragmentAdapter extends CustomFragmentStatePagerAdapter implements TitleProvider {\n    public List<BaseFragment> fragments = new LinkedList<BaseFragment>();\n\n    private int actPage;\n\n    public FragmentAdapter(FragmentManager fm) {\n        super(fm);\n    }\n\n    public void setActPage(int actPage) {\n        this.actPage = actPage;\n    }\n\n    public void addItem(BaseFragment fragment) {\n        // TODO if exists don\'t open / change to that tab\n        fragments.add(fragment);\n    }\n\n    public BaseFragment getActFragment() {\n        return getItem(getActPage());\n    }\n\n    public int getActPage() {\n        return actPage;\n    }\n\n    @Override\n    public BaseFragment getItem(int position) {\n        if (position < getCount()) {\n            return fragments.get(position);\n        } else\n            return null;\n    }\n\n    @Override\n    public int getCount() {\n        return fragments.size();\n    }\n\n    @Override\n    public String getTitle(int position) {\n        return fragments.get(position).getTitle();\n    }\n\n    @Override\n    public int getItemPosition(Object object) {\n        return POSITION_NONE;\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

这就是我删除片段的方式。(我知道它不仅仅是 .remove() )。可以随意改进我的解决方案,您也可以在适配器中的某个位置添加此代码,所以是的。这取决于尝试实现此操作的用户。我在TabHelper.java中使用它(处理所有选项卡操作的类,如删除、添加等)

\n\n
    int act = Cfg.mPager.getCurrentItem();\n    Cfg.mPager.removeAllViews();\n    Cfg.mAdapter.mFragments.remove(act);\n    try {\n        Cfg.mAdapter.mSavedState.remove(act);\n    } catch (Exception ex) {/* Already removed */}\n    try {\n        Cfg.mAdapter.fragments.remove(act);\n    } catch (Exception ex) {/* Already removed */}\n\n    Cfg.mAdapter.notifyDataSetChanged();\n    Cfg.mIndicator.notifyDataSetChanged();\n
Run Code Online (Sandbox Code Playgroud)\n\n

Cfg 的描述 事物。我将对这些对象的引用保存在 cfg 类中,这样我就可以随时使用它们,而不需要特殊的 Factory.java ...

\n\n

是的。我希望我能提供帮助。请随意改进这一点,但请告诉我,以便我也可以改进我的代码。

\n\n

谢谢。

\n\n

如果我错过了任何代码,请告诉我。

\n\n
\n\n

我的旧答案也有效,但前提是您有不同的片段。FileFragment、WebFragment...如果您两次使用其中一种片段类型,则不会。

\n\n

我现在已经让它伪工作了。这是一个非常肮脏的解决方案,我仍在寻找更好的解决方案。请帮忙。

\n\n

我更改了代码,删除了此选项卡:

\n\n
   public static void deleteActTab()\n        {   \n            //We set this on the indicator, NOT the pager\n            int act = Cfg.mPager.getCurrentItem();\n            Cfg.mAdapter.removeItem(act);\n            List<BaseFragment> frags = new LinkedList<BaseFragment>();\n            frags = Cfg.mAdapter.fragments;\n\n            Cfg.mPager = (ViewPager)Cfg.act.findViewById(R.id.pager);\n            Cfg.mPager.setAdapter(Cfg.mAdapter);\n            Cfg.mIndicator.setViewPager(Cfg.mPager);\n\n            Cfg.mAdapter.fragments = frags;\n\n            if(act > 0)\n            {\n                Cfg.mPager.setCurrentItem(act-1);\n                Cfg.mIndicator.setCurrentItem(act-1);\n            }\n\n            Cfg.mIndicator.notifyDataSetChanged();\n        }\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果有人可以改进此代码,请告诉我。如果有人能告诉我们这个问题的真正答案。请在此处添加。有很多很多人都遇到过这个问题。我为解决这个问题的人增加了 50 的声望。我还可以为解决这个问题的人捐款。

\n\n

谢谢

\n