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)
是的,我希望有人可以帮助我.
如果我忘记了什么让我知道.
先谢谢你,迈克
好吧,我现在已经以一种黑客的方式解决了我的问题,但是是的,它正在工作;)。如果有人可以改进我的解决方案,请告诉我。对于我的新解决方案,我现在使用 CustomFragmentStatePagerAdapter 但它不会像应有的那样保存状态并将所有片段存储在列表中。如果用户有超过 50 个片段,这可能会导致内存问题,就像普通的 FragmentPagerAdapter 那样。如果有人可以将状态事物添加回我的解决方案而不删除我的修复,那就太好了。谢谢。
\n\n这是我的CustomFragmentStatePagerAdapter.java
\n\npackage 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}\nRun Code Online (Sandbox Code Playgroud)\n\n这是我正常的FragmentAdapter.java
\n\npackage 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}\nRun 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();\nRun Code Online (Sandbox Code Playgroud)\n\nCfg 的描述 事物。我将对这些对象的引用保存在 cfg 类中,这样我就可以随时使用它们,而不需要特殊的 Factory.java ...
\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 }\nRun Code Online (Sandbox Code Playgroud)\n\n如果有人可以改进此代码,请告诉我。如果有人能告诉我们这个问题的真正答案。请在此处添加。有很多很多人都遇到过这个问题。我为解决这个问题的人增加了 50 的声望。我还可以为解决这个问题的人捐款。
\n\n谢谢
\n