(如果有人需要更多信息或更好的描述,请告知我们)
你好我今天在我的项目中包含了viewPagerLibrary:http://viewpagerindicator.com/#introduction。
不,我得到一个非常奇怪的问题: 如果我添加一个网站或页面(让我们在接下来的几行中称它为网站)并再次将其删除,一切正常。但是,如果我尝试添加不同的页面(那些页面是实现BaseFragment类的不同Fragements),则会显示第一页的内容。 如果我添加几个页面并在这些页面之间删除一个页面,则会发生同样的事情。删除页面之后的页面现在显示已删除的页面内容。
此错误的一个示例: 现在的问题是。如果我在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);
(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();
}
}
是的,我希望有人可以帮助我。
如果我忘记了什么让我知道。
提前致谢, 麦克
答案 0 :(得分:2)
好的,我现在以一种黑客的方式解决了我的问题,但是,它正在发挥作用;)。如果有人可以改进我的解决方案,请告诉我。对于我的新解决方案,我现在使用CustomFragmentStatePagerAdapter,但它不会保存状态,并将所有片段存储在列表中。如果用户有超过50个片段,这可能会导致内存问题,就像普通的FragmentPagerAdapter一样。如果有人可以在不删除我的修复程序的情况下将State-thing添加回我的解决方案,那就太棒了。感谢。
所以这是我的 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 中使用它(一个处理所有标签操作的类,如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();
制造商的描述。事情。我在cfg,class中保存了对这些对象的引用,所以我总是可以使用它们,而不需要特殊的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的声誉。我也可以为解决它的人捐款。
由于
答案 1 :(得分:0)
在您的回答中(通过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();
}
您是否考虑过使用HashMap<Integer, Fragment>
或ArrayAdapter<Fragment>
来改善效果或已使用它?
另外,为什么在BaseFragment中使用静态方法?如果这些泄漏内存,请考虑使用MAT或logcat检查内存使用情况。
答案 2 :(得分:0)
要避免此问题,您必须从 backstack 中删除指定的片段。每次从列表中删除片段时,它都会保留在 backstack 中,因此内容将保留。在从列表中删除片段之前,您必须使用FragmentTransaction删除页面。然后代码可能是这样的。
i < 5
如果您没有删除当前页面后索引的所有页面,并且只从 backstack 中删除当前页面,则可能会抛出异常。