Android adding/removing 个页面时,FragmentStatePagerAdapter 未正确更新 ViewPager
Android FragmentStatePagerAdapter not updating ViewPager correctly when adding/removing pages
我正在尝试创建一个带有选项卡的浏览器,您可以轻松地添加、删除和在它们之间滑动。目前我有一个 ViewPager,每个分页片段都包含一个 WebView 和一些按钮。
问题是我似乎无法在添加或删除选项卡后可靠地更新 ViewPager。我认为这在一定程度上是由 FragmentStatePagerAdapter 中的错误引起的,但解决方法似乎不适用于我的用例,或者我无法实现它们(我是 Android+Java菜鸟)。
理想情况下,添加和删除选项卡不会导致任何 pages/tabs 中的 WebView 被不必要地重新加载。最起码要恢复到原来的样子。
目前有两个具体问题:
在特定位置添加制表符会导致最后一页出现空白片段。如果我在末尾添加一个新标签,它就可以正常工作。
删除选项卡会正确更新选项卡,但如果之后添加新选项卡,我会在最后一页看到一个完全空白的片段。
这是我的适配器代码:
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.app.FragmentTransaction;
import android.view.ViewGroup;
import java.util.ArrayList;
public class BrowserTabRepository extends FragmentStatePagerAdapter {
public Browser browser;
public ArrayList<BrowserTabFragment> mFragmentList = new ArrayList<BrowserTabFragment>();
public boolean removing;
public BrowserTabRepository(FragmentManager fm, Browser browser) {
super(fm);
this.browser = browser;
}
public BrowserTabRepository(FragmentManager fm) {
super(fm);
}
@Override
public BrowserTabFragment getItem(int position) {
return mFragmentList.get(position);
}
public boolean hasItem(int position) {
return position < mFragmentList.size();
}
public void clearAllItems() {
mFragmentList.clear();
this.notifyDataSetChanged();
}
public void updateItem(int position, BrowserTabFragment fragment) {
mFragmentList.set(position, fragment);
notifyDataSetChanged();
}
@Override
public int getItemPosition(Object object) {
// if(removing)return POSITION_NONE; workaround/hack I found. Tabs don't get messed up but the adapter incorrectly returns the state of the fragment that has just been deleted instead of the one replacing it
if (mFragmentList.contains(object)) {
final int index = mFragmentList.indexOf(object);
return index;
}
return POSITION_NONE;
}
public void removeBrowserTab(int position, BrowserTabViewPager viewPager) {
BrowserTabFragment fragment = mFragmentList.get(position);
if (fragment != null) {
removing = true;
//fragment.isBeingRemoved = true;
mFragmentList.remove(fragment);
destroyFragmentView(viewPager, position, fragment);
notifyDataSetChanged();
removing = false;
}
;
}
protected void destroyFragmentView(ViewGroup container, int position, Object object) {
FragmentManager manager = ((Fragment) object).getFragmentManager();
FragmentTransaction trans = manager.beginTransaction();
trans.remove((Fragment) object);
trans.commit();
}
@Override
public int getCount() {
return mFragmentList.size();
}
public void addBrowserTab(BrowserTabFragment fragment, int positionToAdd) {
mFragmentList.add(positionToAdd, fragment);
notifyDataSetChanged();
}
public void addBrowserTab(BrowserTabFragment fragment) {
mFragmentList.add(fragment);
notifyDataSetChanged();
}
}
这是在我的主程序中创建适配器+viewpager 的代码Activity:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_browser);
browserTabRepository = new BrowserTabRepository(this.getSupportFragmentManager(), this);
viewPager = (BrowserTabViewPager) findViewById(R.id.viewPagerContainer);
viewPager.setAdapter(browserTabRepository);
viewPager.setSaveFromParentEnabled(false);
viewPager.setOffscreenPageLimit(2); // how many tabs can be held in memory!
}
以下是片段中可能相关的生命周期代码:
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
webView.saveState(outState); // save state of web view when it is paused (in background, rotated etc)
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_browser, container, false);
webView = (CustomWebView) rootView.findViewById(R.id.activity_main_webview);
// ... load tab buttons, configure web view and other stuff ...
if(startingPageAddress!=null){
goToAddressOrSearchString(startingPageAddress);
startingPageAddress = null;
}else if(savedInstanceState!=null) {
webView.restoreState(savedInstanceState); // restore state of bundle
}
return rootView;
}
我最终放弃了这种方法,因为它是 FragmentStatePagerAdapter 的一个长期存在的错误,我无法根据高度动态选项卡的要求修复 100%。
我发现一个更好的解决方案是切换到使用 RecyclerView + PagerSnapHelper + RecyclerView.Adapter 因为它的工作方式几乎相同但没有错误
我正在尝试创建一个带有选项卡的浏览器,您可以轻松地添加、删除和在它们之间滑动。目前我有一个 ViewPager,每个分页片段都包含一个 WebView 和一些按钮。
问题是我似乎无法在添加或删除选项卡后可靠地更新 ViewPager。我认为这在一定程度上是由 FragmentStatePagerAdapter 中的错误引起的,但解决方法似乎不适用于我的用例,或者我无法实现它们(我是 Android+Java菜鸟)。
理想情况下,添加和删除选项卡不会导致任何 pages/tabs 中的 WebView 被不必要地重新加载。最起码要恢复到原来的样子。
目前有两个具体问题:
在特定位置添加制表符会导致最后一页出现空白片段。如果我在末尾添加一个新标签,它就可以正常工作。
删除选项卡会正确更新选项卡,但如果之后添加新选项卡,我会在最后一页看到一个完全空白的片段。
这是我的适配器代码:
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.app.FragmentTransaction;
import android.view.ViewGroup;
import java.util.ArrayList;
public class BrowserTabRepository extends FragmentStatePagerAdapter {
public Browser browser;
public ArrayList<BrowserTabFragment> mFragmentList = new ArrayList<BrowserTabFragment>();
public boolean removing;
public BrowserTabRepository(FragmentManager fm, Browser browser) {
super(fm);
this.browser = browser;
}
public BrowserTabRepository(FragmentManager fm) {
super(fm);
}
@Override
public BrowserTabFragment getItem(int position) {
return mFragmentList.get(position);
}
public boolean hasItem(int position) {
return position < mFragmentList.size();
}
public void clearAllItems() {
mFragmentList.clear();
this.notifyDataSetChanged();
}
public void updateItem(int position, BrowserTabFragment fragment) {
mFragmentList.set(position, fragment);
notifyDataSetChanged();
}
@Override
public int getItemPosition(Object object) {
// if(removing)return POSITION_NONE; workaround/hack I found. Tabs don't get messed up but the adapter incorrectly returns the state of the fragment that has just been deleted instead of the one replacing it
if (mFragmentList.contains(object)) {
final int index = mFragmentList.indexOf(object);
return index;
}
return POSITION_NONE;
}
public void removeBrowserTab(int position, BrowserTabViewPager viewPager) {
BrowserTabFragment fragment = mFragmentList.get(position);
if (fragment != null) {
removing = true;
//fragment.isBeingRemoved = true;
mFragmentList.remove(fragment);
destroyFragmentView(viewPager, position, fragment);
notifyDataSetChanged();
removing = false;
}
;
}
protected void destroyFragmentView(ViewGroup container, int position, Object object) {
FragmentManager manager = ((Fragment) object).getFragmentManager();
FragmentTransaction trans = manager.beginTransaction();
trans.remove((Fragment) object);
trans.commit();
}
@Override
public int getCount() {
return mFragmentList.size();
}
public void addBrowserTab(BrowserTabFragment fragment, int positionToAdd) {
mFragmentList.add(positionToAdd, fragment);
notifyDataSetChanged();
}
public void addBrowserTab(BrowserTabFragment fragment) {
mFragmentList.add(fragment);
notifyDataSetChanged();
}
}
这是在我的主程序中创建适配器+viewpager 的代码Activity:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_browser);
browserTabRepository = new BrowserTabRepository(this.getSupportFragmentManager(), this);
viewPager = (BrowserTabViewPager) findViewById(R.id.viewPagerContainer);
viewPager.setAdapter(browserTabRepository);
viewPager.setSaveFromParentEnabled(false);
viewPager.setOffscreenPageLimit(2); // how many tabs can be held in memory!
}
以下是片段中可能相关的生命周期代码:
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
webView.saveState(outState); // save state of web view when it is paused (in background, rotated etc)
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_browser, container, false);
webView = (CustomWebView) rootView.findViewById(R.id.activity_main_webview);
// ... load tab buttons, configure web view and other stuff ...
if(startingPageAddress!=null){
goToAddressOrSearchString(startingPageAddress);
startingPageAddress = null;
}else if(savedInstanceState!=null) {
webView.restoreState(savedInstanceState); // restore state of bundle
}
return rootView;
}
我最终放弃了这种方法,因为它是 FragmentStatePagerAdapter 的一个长期存在的错误,我无法根据高度动态选项卡的要求修复 100%。
我发现一个更好的解决方案是切换到使用 RecyclerView + PagerSnapHelper + RecyclerView.Adapter 因为它的工作方式几乎相同但没有错误