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

发布于 2024-12-29 19:32:58 字数 5677 浏览 3 评论 0原文

(如果有人需要更多信息或更好的描述,请告诉我)

您好,我从这里添加了 viewPagerLibrary:http://viewpagerindicator.com/#introduction">http://viewpagerlibrary /viewpagerindicator.com/#introduction 今天在我的项目中。

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

此错误的示例: 现在的问题是。如果我在 FragmentB 之后添加 FragmentA,那么我删除 FragmentA,FragmentB 会获取 FragmentA 的视图/内容。奇怪的是,对象是正确的(因此适配器返回正确的对象)并且标题也是正确的。

在我的 main 中,我以这种方式创建我的寻呼机、指示器和适配器:

    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);

(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;
    }
}

其中一个片段如下所示(我认为其他片段使没有区别):

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);
}

}

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

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();
}

这就是适配器:

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();
    }

}

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

如果我忘记了什么,请告诉我。

提前致谢, 麦克风

(If someone needs more information, or a better description let me know)

Hello i included the viewPagerLibrary from here: http://viewpagerindicator.com/#introduction today in my project.

No i get a really strange problem:
If i add a site or page (let's call it site in the next few lines) and remove it again everything is ok. But if i try to add a different page (Those pages are different Fragements which implements a BaseFragment class) the content of the first page is shown.
The same thing happens if i add a few pages and delete one inbetween those pages. The page which was after the deleted page shows now the deleted pages content.

An example of this bug:
The problem now is. If i add FragmentA after that FragmentB, then i delete FragmentA, FragmentB gets the view/content of FragmentA. The strange thing is, the object is the correct one (So the adapter return the correct object) and the Title is also the correct one.

In my main i create my Pager, Indicator and Adapter this way:

    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);

(The Cfg is a static file to store those things for the usage)

My BaseFragment looks like the following:

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;
    }
}

One of the Fragments looks like this (I think the other fragments make no difference):

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);
}

}

To remove or add a page i call this:

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();
}

And that's the adapter:

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();
    }

}

Yeah i hope someone can help me.

If i forgot something let me konw.

Thanks in advance,
Mike

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

嗳卜坏 2025-01-05 19:32:58

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

这是我的 CustomFragmentStatePagerAdapter.java

package com.tundem.webLab.Adapter;

import java.util.ArrayList;

import android.os.Bundle;
import android.os.Parcelable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.PagerAdapter;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;

public abstract class CustomFragmentStatePagerAdapter extends PagerAdapter {
    private static final String TAG = "FragmentStatePagerAdapter";
    private static final boolean DEBUG = false;

    private final FragmentManager mFragmentManager;
    private FragmentTransaction mCurTransaction = null;

    public ArrayList<Fragment.SavedState> mSavedState = new ArrayList<Fragment.SavedState>();
    public ArrayList<Fragment> mFragments = new ArrayList<Fragment>();
    private Fragment mCurrentPrimaryItem = null;

    public CustomFragmentStatePagerAdapter(FragmentManager fm) {
        mFragmentManager = fm;
    }

    /**
     * Return the Fragment associated with a specified position.
     */
    public abstract Fragment getItem(int position);

    @Override
    public void startUpdate(ViewGroup container) {}

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        // If we already have this item instantiated, there is nothing
        // to do. This can happen when we are restoring the entire pager
        // from its saved state, where the fragment manager has already
        // taken care of restoring the fragments we previously had instantiated.

        // DONE Remove of the add process of the old stuff
        /* if (mFragments.size() > position) { Fragment f = mFragments.get(position); if (f != null) { return f; } } */

        if (mCurTransaction == null) {
            mCurTransaction = mFragmentManager.beginTransaction();
        }

        Fragment fragment = getItem(position);
        if (DEBUG)
            Log.v(TAG, "Adding item #" + position + ": f=" + fragment);
        if (mSavedState.size() > position) {
            Fragment.SavedState fss = mSavedState.get(position);
            if (fss != null) {
                try // DONE: Try Catch
                {
                    fragment.setInitialSavedState(fss);
                } catch (Exception ex) {
                    // Schon aktiv (kA was das heißt xD)
                }
            }
        }
        while (mFragments.size() <= position) {
            mFragments.add(null);
        }
        fragment.setMenuVisibility(false);
        mFragments.set(position, fragment);
        mCurTransaction.add(container.getId(), fragment);

        return fragment;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        Fragment fragment = (Fragment) object;

        if (mCurTransaction == null) {
            mCurTransaction = mFragmentManager.beginTransaction();
        }
        mCurTransaction.remove(fragment);

        /*if (mCurTransaction == null) { mCurTransaction = mFragmentManager.beginTransaction(); } if (DEBUG) Log.v(TAG, "Removing item #" + position + ": f=" + object + " v=" + ((Fragment)
         * object).getView()); while (mSavedState.size() <= position) { mSavedState.add(null); } mSavedState.set(position, mFragmentManager.saveFragmentInstanceState(fragment));
         * mFragments.set(position, null); mCurTransaction.remove(fragment); */
    }

    @Override
    public void setPrimaryItem(ViewGroup container, int position, Object object) {
        Fragment fragment = (Fragment) object;
        if (fragment != mCurrentPrimaryItem) {
            if (mCurrentPrimaryItem != null) {
                mCurrentPrimaryItem.setMenuVisibility(false);
            }
            if (fragment != null) {
                fragment.setMenuVisibility(true);
            }
            mCurrentPrimaryItem = fragment;
        }
    }

    @Override
    public void finishUpdate(ViewGroup container) {
        if (mCurTransaction != null) {
            mCurTransaction.commitAllowingStateLoss();
            mCurTransaction = null;
            mFragmentManager.executePendingTransactions();
        }
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return ((Fragment) object).getView() == view;
    }

    @Override
    public Parcelable saveState() {
        Bundle state = null;
        if (mSavedState.size() > 0) {
            state = new Bundle();
            Fragment.SavedState[] fss = new Fragment.SavedState[mSavedState.size()];
            mSavedState.toArray(fss);
            state.putParcelableArray("states", fss);
        }
        for (int i = 0; i < mFragments.size(); i++) {
            Fragment f = mFragments.get(i);
            if (f != null) {
                if (state == null) {
                    state = new Bundle();
                }
                String key = "f" + i;
                mFragmentManager.putFragment(state, key, f);
            }
        }
        return state;
    }

    @Override
    public void restoreState(Parcelable state, ClassLoader loader) {
        if (state != null) {
            Bundle bundle = (Bundle) state;
            bundle.setClassLoader(loader);
            Parcelable[] fss = bundle.getParcelableArray("states");
            mSavedState.clear();
            mFragments.clear();
            if (fss != null) {
                for (int i = 0; i < fss.length; i++) {
                    mSavedState.add((Fragment.SavedState) fss[i]);
                }
            }
            Iterable<String> keys = bundle.keySet();
            for (String key : keys) {
                if (key.startsWith("f")) {
                    int index = Integer.parseInt(key.substring(1));
                    Fragment f = mFragmentManager.getFragment(bundle, key);
                    if (f != null) {
                        while (mFragments.size() <= index) {
                            mFragments.add(null);
                        }
                        f.setMenuVisibility(false);
                        mFragments.set(index, f);
                    } else {
                        Log.w(TAG, "Bad fragment at key " + key);
                    }
                }
            }
        }
    }
}

这是我正常的 FragmentAdapter.java

package com.tundem.webLab.Adapter;

import java.util.LinkedList;
import java.util.List;

import android.support.v4.app.FragmentManager;

import com.tundem.webLab.fragments.BaseFragment;
import com.viewpagerindicator.TitleProvider;

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

    private int actPage;

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

    public void setActPage(int actPage) {
        this.actPage = actPage;
    }

    public void addItem(BaseFragment fragment) {
        // TODO if exists don't open / change to that tab
        fragments.add(fragment);
    }

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

    public int getActPage() {
        return actPage;
    }

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

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

    @Override
    public String getTitle(int position) {
        return fragments.get(position).getTitle();
    }

    @Override
    public int getItemPosition(Object object) {
        return POSITION_NONE;
    }
}

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

    int act = Cfg.mPager.getCurrentItem();
    Cfg.mPager.removeAllViews();
    Cfg.mAdapter.mFragments.remove(act);
    try {
        Cfg.mAdapter.mSavedState.remove(act);
    } catch (Exception ex) {/* Already removed */}
    try {
        Cfg.mAdapter.fragments.remove(act);
    } catch (Exception ex) {/* Already removed */}

    Cfg.mAdapter.notifyDataSetChanged();
    Cfg.mIndicator.notifyDataSetChanged();

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

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

谢谢。

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


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

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

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

   public static void deleteActTab()
        {   
            //We set this on the indicator, NOT the pager
            int act = Cfg.mPager.getCurrentItem();
            Cfg.mAdapter.removeItem(act);
            List<BaseFragment> frags = new LinkedList<BaseFragment>();
            frags = Cfg.mAdapter.fragments;

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

            Cfg.mAdapter.fragments = frags;

            if(act > 0)
            {
                Cfg.mPager.setCurrentItem(act-1);
                Cfg.mIndicator.setCurrentItem(act-1);
            }

            Cfg.mIndicator.notifyDataSetChanged();
        }

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

谢谢

Ok i've now solved my problem in a hackish way, but yeah it's working ;). If someone can improve my solution please let me know. For my new solution i now use a CustomFragmentStatePagerAdapter but it doesn't save the state like it should and stores all the Fragments in a list. This can cause a memory problem if the user has more than 50 fragments, like the normal FragmentPagerAdapter does. It would be great if someone can add the State-thing back to my solution without removing my fixes. Thanks.

So here's my CustomFragmentStatePagerAdapter.java

package com.tundem.webLab.Adapter;

import java.util.ArrayList;

import android.os.Bundle;
import android.os.Parcelable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.PagerAdapter;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;

public abstract class CustomFragmentStatePagerAdapter extends PagerAdapter {
    private static final String TAG = "FragmentStatePagerAdapter";
    private static final boolean DEBUG = false;

    private final FragmentManager mFragmentManager;
    private FragmentTransaction mCurTransaction = null;

    public ArrayList<Fragment.SavedState> mSavedState = new ArrayList<Fragment.SavedState>();
    public ArrayList<Fragment> mFragments = new ArrayList<Fragment>();
    private Fragment mCurrentPrimaryItem = null;

    public CustomFragmentStatePagerAdapter(FragmentManager fm) {
        mFragmentManager = fm;
    }

    /**
     * Return the Fragment associated with a specified position.
     */
    public abstract Fragment getItem(int position);

    @Override
    public void startUpdate(ViewGroup container) {}

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        // If we already have this item instantiated, there is nothing
        // to do. This can happen when we are restoring the entire pager
        // from its saved state, where the fragment manager has already
        // taken care of restoring the fragments we previously had instantiated.

        // DONE Remove of the add process of the old stuff
        /* if (mFragments.size() > position) { Fragment f = mFragments.get(position); if (f != null) { return f; } } */

        if (mCurTransaction == null) {
            mCurTransaction = mFragmentManager.beginTransaction();
        }

        Fragment fragment = getItem(position);
        if (DEBUG)
            Log.v(TAG, "Adding item #" + position + ": f=" + fragment);
        if (mSavedState.size() > position) {
            Fragment.SavedState fss = mSavedState.get(position);
            if (fss != null) {
                try // DONE: Try Catch
                {
                    fragment.setInitialSavedState(fss);
                } catch (Exception ex) {
                    // Schon aktiv (kA was das heißt xD)
                }
            }
        }
        while (mFragments.size() <= position) {
            mFragments.add(null);
        }
        fragment.setMenuVisibility(false);
        mFragments.set(position, fragment);
        mCurTransaction.add(container.getId(), fragment);

        return fragment;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        Fragment fragment = (Fragment) object;

        if (mCurTransaction == null) {
            mCurTransaction = mFragmentManager.beginTransaction();
        }
        mCurTransaction.remove(fragment);

        /*if (mCurTransaction == null) { mCurTransaction = mFragmentManager.beginTransaction(); } if (DEBUG) Log.v(TAG, "Removing item #" + position + ": f=" + object + " v=" + ((Fragment)
         * object).getView()); while (mSavedState.size() <= position) { mSavedState.add(null); } mSavedState.set(position, mFragmentManager.saveFragmentInstanceState(fragment));
         * mFragments.set(position, null); mCurTransaction.remove(fragment); */
    }

    @Override
    public void setPrimaryItem(ViewGroup container, int position, Object object) {
        Fragment fragment = (Fragment) object;
        if (fragment != mCurrentPrimaryItem) {
            if (mCurrentPrimaryItem != null) {
                mCurrentPrimaryItem.setMenuVisibility(false);
            }
            if (fragment != null) {
                fragment.setMenuVisibility(true);
            }
            mCurrentPrimaryItem = fragment;
        }
    }

    @Override
    public void finishUpdate(ViewGroup container) {
        if (mCurTransaction != null) {
            mCurTransaction.commitAllowingStateLoss();
            mCurTransaction = null;
            mFragmentManager.executePendingTransactions();
        }
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return ((Fragment) object).getView() == view;
    }

    @Override
    public Parcelable saveState() {
        Bundle state = null;
        if (mSavedState.size() > 0) {
            state = new Bundle();
            Fragment.SavedState[] fss = new Fragment.SavedState[mSavedState.size()];
            mSavedState.toArray(fss);
            state.putParcelableArray("states", fss);
        }
        for (int i = 0; i < mFragments.size(); i++) {
            Fragment f = mFragments.get(i);
            if (f != null) {
                if (state == null) {
                    state = new Bundle();
                }
                String key = "f" + i;
                mFragmentManager.putFragment(state, key, f);
            }
        }
        return state;
    }

    @Override
    public void restoreState(Parcelable state, ClassLoader loader) {
        if (state != null) {
            Bundle bundle = (Bundle) state;
            bundle.setClassLoader(loader);
            Parcelable[] fss = bundle.getParcelableArray("states");
            mSavedState.clear();
            mFragments.clear();
            if (fss != null) {
                for (int i = 0; i < fss.length; i++) {
                    mSavedState.add((Fragment.SavedState) fss[i]);
                }
            }
            Iterable<String> keys = bundle.keySet();
            for (String key : keys) {
                if (key.startsWith("f")) {
                    int index = Integer.parseInt(key.substring(1));
                    Fragment f = mFragmentManager.getFragment(bundle, key);
                    if (f != null) {
                        while (mFragments.size() <= index) {
                            mFragments.add(null);
                        }
                        f.setMenuVisibility(false);
                        mFragments.set(index, f);
                    } else {
                        Log.w(TAG, "Bad fragment at key " + key);
                    }
                }
            }
        }
    }
}

Here's my normal FragmentAdapter.java

package com.tundem.webLab.Adapter;

import java.util.LinkedList;
import java.util.List;

import android.support.v4.app.FragmentManager;

import com.tundem.webLab.fragments.BaseFragment;
import com.viewpagerindicator.TitleProvider;

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

    private int actPage;

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

    public void setActPage(int actPage) {
        this.actPage = actPage;
    }

    public void addItem(BaseFragment fragment) {
        // TODO if exists don't open / change to that tab
        fragments.add(fragment);
    }

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

    public int getActPage() {
        return actPage;
    }

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

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

    @Override
    public String getTitle(int position) {
        return fragments.get(position).getTitle();
    }

    @Override
    public int getItemPosition(Object object) {
        return POSITION_NONE;
    }
}

And this is the way i delete a Fragment. (I know it's a bit more than only .remove() ). Be free to improve my solution, you can also add this code somewhere in the adapter so yeah. It's up to the user who tries to implement this. I use this in my TabHelper.java (A class which handles all tab operations like delete, add, ...)

    int act = Cfg.mPager.getCurrentItem();
    Cfg.mPager.removeAllViews();
    Cfg.mAdapter.mFragments.remove(act);
    try {
        Cfg.mAdapter.mSavedState.remove(act);
    } catch (Exception ex) {/* Already removed */}
    try {
        Cfg.mAdapter.fragments.remove(act);
    } catch (Exception ex) {/* Already removed */}

    Cfg.mAdapter.notifyDataSetChanged();
    Cfg.mIndicator.notifyDataSetChanged();

Description of the Cfg. thing. I save the reference to those objects in a cfg, class so i can always use them without the need of a special Factory.java ...

Yeah. i hope i was able to help. Feel free to improve this, but let me know so i can improve my code too.

Thanks.

If i missed any code let me know.


My old answer also works but only if you have different Fragments. FileFragment, WebFragment, ... Not if you use one of those fragmenttypes twice.

I got it pseudo working for now. It's a really dirty solution and i'm still searching for a better one. Please help.

I changed the code, where i delete a tab to this one:

   public static void deleteActTab()
        {   
            //We set this on the indicator, NOT the pager
            int act = Cfg.mPager.getCurrentItem();
            Cfg.mAdapter.removeItem(act);
            List<BaseFragment> frags = new LinkedList<BaseFragment>();
            frags = Cfg.mAdapter.fragments;

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

            Cfg.mAdapter.fragments = frags;

            if(act > 0)
            {
                Cfg.mPager.setCurrentItem(act-1);
                Cfg.mIndicator.setCurrentItem(act-1);
            }

            Cfg.mIndicator.notifyDataSetChanged();
        }

If someone can improve this code let me know. If someone can tell us the real answer for that problem. please add it here. There are many many people who experience this issue. I added a reputation of 50 for the one who solve it. I can also give a donation for the one who solve it.

Thanks

初见你 2025-01-05 19:32:58

在您的回答(作者:mikepenz)中,您不需要再次设置适配器。您可以调用notifyDataSetChanged。

public static void deleteActTab(){

        //We set this on the indicator, NOT the pager
        int act = Cfg.mPager.getCurrentItem();
        Cfg.mAdapter.removeItem(act);        


        if(act > 0)
        {
            Cfg.mPager.setCurrentItem(act-1);
            Cfg.mIndicator.setCurrentItem(act-1);
        }
       //Also add conditions to check if there are any remaining fragments


        Cfg.mIndicator.notifyDataSetChanged();
}

您是否考虑过使用 HashMapArrayAdapter 来提高性能或者已经在使用它?
另外,为什么在 BaseFragment 中使用静态方法?如果这些泄漏内存,请考虑使用 MAT 或 logcat 检查内存使用情况。

In your answer (by mikepenz), you don't need to set the adapter again. You may call the notifyDataSetChanged.

public static void deleteActTab(){

        //We set this on the indicator, NOT the pager
        int act = Cfg.mPager.getCurrentItem();
        Cfg.mAdapter.removeItem(act);        


        if(act > 0)
        {
            Cfg.mPager.setCurrentItem(act-1);
            Cfg.mIndicator.setCurrentItem(act-1);
        }
       //Also add conditions to check if there are any remaining fragments


        Cfg.mIndicator.notifyDataSetChanged();
}

Did you consider using HashMap<Integer, Fragment> or ArrayAdapter<Fragment> to improve the performance or already using it?
Also, why do you use static method in BaseFragment? Please consider using MAT or logcat to check memory usage if these leak memory.

°如果伤别离去 2025-01-05 19:32:58

为了避免这个问题,您必须从backstack中删除指定的片段。每次从列表中删除片段时,它都会保留在backstack中,因此内容将保留。在从列表中删除片段之前,您必须使用 FragmentTransaction 来删除页面。那么代码可能是这样的。

public void removePage(int currentPage) {
    for (int i = pageFragmentList.size() - 1; i >= currentPage; i--) {
        ((MainActivity) context).getSupportFragmentManager().beginTransaction()
                .remove(pageFragmentList.get(i)).commit();
    }
    pageFragmentList.remove(currentPage);
}

如果您不删除当前页面之后索引的所有页面,而仅从 backstack 中删除当前页面,则可能会引发异常。

To avoid this problem you have to remove the specified fragment from backstack. Every time you delete a fragment from your list, it remains in backstack so the content will remain. Before deleting the fragment from your list you have to use FragmentTransaction to remove the page. Then the code might be something like this.

public void removePage(int currentPage) {
    for (int i = pageFragmentList.size() - 1; i >= currentPage; i--) {
        ((MainActivity) context).getSupportFragmentManager().beginTransaction()
                .remove(pageFragmentList.get(i)).commit();
    }
    pageFragmentList.remove(currentPage);
}

If you don't remove all the pages indexed after the current page, and only remove the current page from backstack, it might throw an exception.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文